From 1016409957c98026ae0135a607617f3e56cf6c7b Mon Sep 17 00:00:00 2001 From: Junghoon Kim Date: Mon, 20 Jan 2025 21:24:49 +0900 Subject: [PATCH 1/2] :clock: recalled to before jwtAuthenticationFilter was simplified --- .../security/JwtAuthenticationFilter.kt | 31 ++++++++----- .../karrot/user/persistence/UserPrincipal.kt | 43 +++++++++++++++++++ .../karrot/user/service/UserService.kt | 10 +++++ 3 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt diff --git a/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt b/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt index f485045..567cd5e 100644 --- a/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt @@ -1,20 +1,20 @@ package com.toyProject7.karrot.security - import com.toyProject7.karrot.user.UserAccessTokenUtil import com.toyProject7.karrot.user.service.UserService import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.stereotype.Component import org.springframework.web.filter.OncePerRequestFilter - @Component class JwtAuthenticationFilter( private val userService: UserService, ) : OncePerRequestFilter() { private val excludedPaths = SecurityConstants.PUBLIC_PATHS.map { AntPathRequestMatcher(it) } - override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, @@ -25,27 +25,38 @@ class JwtAuthenticationFilter( filterChain.doFilter(request, response) return } - val authHeader = request.getHeader("Authorization") - if (authHeader != null && authHeader.startsWith("Bearer ")) { val token = authHeader.substring(7) - try { // Validate the token if (UserAccessTokenUtil.validateToken(token)) { - // do nothing + // Get user ID from token + val userId = UserAccessTokenUtil.getUserIdFromToken(token) + + // Load user details + val userDetails = userService.loadSocialUserById(userId) + + // Create authentication token + val authentication = + UsernamePasswordAuthenticationToken( + userDetails, + null, + userDetails.authorities, + ) + authentication.details = WebAuthenticationDetailsSource().buildDetails(request) + + // Set the authentication in the context + SecurityContextHolder.getContext().authentication = authentication } } catch (e: Exception) { // Handle exceptions (e.g., log them) println("Failed to authenticate user: ${e.message}") } } - filterChain.doFilter(request, response) } - private fun isExcluded(request: HttpServletRequest): Boolean { return excludedPaths.any { it.matches(request) } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt b/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt new file mode 100644 index 0000000..d149984 --- /dev/null +++ b/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt @@ -0,0 +1,43 @@ +package com.toyProject7.karrot.user.persistence + +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.UserDetails + +data class UserPrincipal( + val id: String, + private val email: String, + private val nickname: String, + private val password: String?, + private val authorities: Collection, +) : UserDetails { + companion object { + fun create(user: UserEntity): UserPrincipal { + val authorities = listOf(SimpleGrantedAuthority("ROLE_USER")) + + return UserPrincipal( + id = user.id!!, + email = user.email, + nickname = user.nickname, + password = null, + authorities = authorities, + ) + } + } + + override fun getAuthorities(): Collection = authorities + + override fun getPassword(): String? = password + + fun getNickname(): String = nickname + + override fun getUsername(): String = email + + override fun isAccountNonExpired(): Boolean = true + + override fun isAccountNonLocked(): Boolean = true + + override fun isCredentialsNonExpired(): Boolean = true + + override fun isEnabled(): Boolean = true +} \ No newline at end of file diff --git a/src/main/kotlin/com/toyProject7/karrot/user/service/UserService.kt b/src/main/kotlin/com/toyProject7/karrot/user/service/UserService.kt index ec3dc5a..ebaf456 100644 --- a/src/main/kotlin/com/toyProject7/karrot/user/service/UserService.kt +++ b/src/main/kotlin/com/toyProject7/karrot/user/service/UserService.kt @@ -17,9 +17,11 @@ import com.toyProject7.karrot.user.persistence.NormalUser import com.toyProject7.karrot.user.persistence.NormalUserRepository import com.toyProject7.karrot.user.persistence.SocialUser import com.toyProject7.karrot.user.persistence.UserEntity +import com.toyProject7.karrot.user.persistence.UserPrincipal import com.toyProject7.karrot.user.persistence.UserRepository import org.mindrot.jbcrypt.BCrypt import org.springframework.data.repository.findByIdOrNull +import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.time.Instant @@ -144,4 +146,12 @@ class UserService( fun getUserEntityById(id: String): UserEntity { return userRepository.findByIdOrNull(id) ?: throw AuthenticateException() } + + @Transactional + fun loadSocialUserById(id: String): UserPrincipal { + val user = + userRepository.findById(id) + .orElseThrow { UsernameNotFoundException("User not found with id: $id") } + return UserPrincipal.create(user) + } } From d2ac9ea66c5f41d2950760a1b7898aa698e13664 Mon Sep 17 00:00:00 2001 From: Junghoon Kim Date: Mon, 20 Jan 2025 21:26:48 +0900 Subject: [PATCH 2/2] :art: lint --- .../toyProject7/karrot/security/JwtAuthenticationFilter.kt | 5 ++++- .../com/toyProject7/karrot/user/persistence/UserPrincipal.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt b/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt index 567cd5e..c6b3f2d 100644 --- a/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/com/toyProject7/karrot/security/JwtAuthenticationFilter.kt @@ -10,11 +10,13 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.stereotype.Component import org.springframework.web.filter.OncePerRequestFilter + @Component class JwtAuthenticationFilter( private val userService: UserService, ) : OncePerRequestFilter() { private val excludedPaths = SecurityConstants.PUBLIC_PATHS.map { AntPathRequestMatcher(it) } + override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, @@ -56,7 +58,8 @@ class JwtAuthenticationFilter( } filterChain.doFilter(request, response) } + private fun isExcluded(request: HttpServletRequest): Boolean { return excludedPaths.any { it.matches(request) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt b/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt index d149984..491ca5e 100644 --- a/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt +++ b/src/main/kotlin/com/toyProject7/karrot/user/persistence/UserPrincipal.kt @@ -40,4 +40,4 @@ data class UserPrincipal( override fun isCredentialsNonExpired(): Boolean = true override fun isEnabled(): Boolean = true -} \ No newline at end of file +}