Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions authentication/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.coded.spring</groupId>
<artifactId>Ordering</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>authentication</artifactId>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.coded.spring.authentication

import com.coded.spring.users.UserEntity
import com.coded.spring.users.UsersRepository
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.stereotype.Service


@Service
class CustomerDetailsService(
private val userRepo : UsersRepository
): UserDetailsService {
override fun loadUserByUsername(username: String): UserDetails {
val user: UserEntity = userRepo.findByUsername(username) ?:
throw UsernameNotFoundException("User not found ...")

return User.builder()
.username(user.username)
.password(user.password)
.build()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.coded.spring.authentication.JWT

import com.coded.spring.users.UsersService
import org.springframework.security.authentication.*
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.web.bind.annotation.*
import java.security.Principal


@RestController
@RequestMapping("/auth")
class AuthenticationController(
private val authenticationManager: AuthenticationManager,
private val userDetailsService: UserDetailsService,
private val jwtService: JwtService,
private val usersService: UsersService
) {

@PostMapping("/login")
fun login(@RequestBody authRequest: AuthenticationRequest): AuthenticationResponse {
val authToken = UsernamePasswordAuthenticationToken(authRequest.username, authRequest.password)
val authentication = authenticationManager.authenticate(authToken)

if (authentication.isAuthenticated) {
val userDetails = userDetailsService.loadUserByUsername(authRequest.username)
val token = jwtService.generateToken(userDetails.username)
return AuthenticationResponse (token)
} else {
throw UsernameNotFoundException("Invalid user request!")
}
}
@PostMapping("/check-token")
fun checkToken(
principal: Principal
): CheckTokenResponse {
return CheckTokenResponse(
userId = usersService.findByUsername(principal.name)
)
}
}

data class AuthenticationRequest(
val username: String,
val password: String
)

data class AuthenticationResponse(
val token: String
)

data class CheckTokenResponse(
val userId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.coded.spring.authentication.JWT

import jakarta.inject.Named
import jakarta.servlet.FilterChain
import jakarta.servlet.http.*
import org.springframework.context.annotation.Bean
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter



@Component
class JwtAuthenticationFilter(
private val jwtService: JwtService,
private val userDetailsService: UserDetailsService
) : OncePerRequestFilter() {

override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val authHeader = request.getHeader("Authorization")
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response)
return
}

val token = authHeader.substring(7)
val username = jwtService.extractUsername(token)

if (SecurityContextHolder.getContext().authentication == null) {
if (jwtService.isTokenValid(token, username)) {
val userDetails = userDetailsService.loadUserByUsername(username)
val authToken = UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.authorities
)
authToken.details = WebAuthenticationDetailsSource().buildDetails(request)
SecurityContextHolder.getContext().authentication = authToken
}
}

filterChain.doFilter(request, response)
}
}
47 changes: 47 additions & 0 deletions authentication/src/main/kotlin/authentication/JWT/JwtService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.coded.spring.authentication.JWT


import io.jsonwebtoken.*
import io.jsonwebtoken.security.Keys
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.util.*
import javax.crypto.SecretKey

@Component
class JwtService (
@Value("\${jwt-secret}")
private val secretKeyString: String
){
private val secretKey: SecretKey = Keys.hmacShaKeyFor(secretKeyString.encodeToByteArray())
// private val secretKey: SecretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256)
private val expirationMs: Long = 1000 * 60 * 60

fun generateToken(username: String): String {
val now = Date()
val expiry = Date(now.time + expirationMs)

return Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(expiry)
.signWith(secretKey)
.compact()
}

fun extractUsername(token: String): String =
Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.body
.subject

fun isTokenValid(token: String, username: String): Boolean {
return try {
extractUsername(token) == username
} catch (e: Exception) {
false
}
}
}
38 changes: 38 additions & 0 deletions authentication/src/main/kotlin/authentication/Loggerfilter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.coded.spring.authentication

import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import org.springframework.web.util.ContentCachingRequestWrapper
import org.springframework.web.util.ContentCachingResponseWrapper


@Component
class LoggingFilter: OncePerRequestFilter(){
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val cachedRequest = ContentCachingRequestWrapper(request)
val cachedResponse = ContentCachingResponseWrapper(response)

filterChain.doFilter(cachedRequest, cachedResponse)

logRequest(cachedRequest)
logResponse(cachedResponse)
cachedResponse.copyBodyToResponse()
}

private fun logRequest(request: ContentCachingRequestWrapper) {
val requestBody = String(request.contentAsByteArray)
logger.info("Request: method=${request.method}, uri=${request.requestURI}, body=$requestBody")
}

private fun logResponse(response: ContentCachingResponseWrapper) {
val responseBody = String(response.contentAsByteArray)
logger.info("Response: status=${response.status}, body=$responseBody")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.coded.spring.Profiles

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

@RestController
class ProfileController(
val profilesRepository: ProfilesRepository,
val profilesService: ProfilesService
){
@PostMapping("/auth/users/v1/profiles")
fun createProfiles(@RequestBody request: ProfileRequest): ProfileResponse{
return profilesService.createProfile(request)
}

@GetMapping("/auth/users/v1/profiles/list")
fun showProfiles() = profilesRepository.findAll()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.coded.spring.Profiles

import jakarta.persistence.*


@Entity
@Table(name="profiles")
data class ProfileEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
val userID: Long,
val firstName: String,
val lastName: String,
val phoneNumber: Long
){
constructor() : this(null,0, "","",0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.coded.spring.Profiles

import jakarta.inject.Named
import org.springframework.data.jpa.repository.JpaRepository

@Named
interface ProfilesRepository : JpaRepository<ProfileEntity, Long>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.coded.spring.Profiles

import com.coded.spring.users.UsersRepository
import jakarta.inject.Named
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.context.SecurityContextHolder

@Named
class ProfilesService (
private val profilesRepository: ProfilesRepository,
private val usersRepository: UsersRepository
){
fun createProfile(request: ProfileRequest): ProfileResponse{
val userId = usersRepository.findByUsername(SecurityContextHolder.getContext().authentication.name)?.id ?:
throw IllegalArgumentException()
val newProfile = ProfileEntity(
userID = userId,
firstName = request.firstName,
lastName = request.lastName,
phoneNumber = request.phoneNumber
)
val savedProfile = profilesRepository.save(newProfile)
return ProfileResponse(savedProfile.firstName,savedProfile.lastName,savedProfile.phoneNumber)
}
}

data class ProfileRequest(
val firstName: String,
val lastName: String,
val phoneNumber: Long
)

data class ProfileResponse(
val firstName: String,
val lastName: String,
val phoneNumber: Long

)

Loading