Skip to content

Commit

Permalink
Modify/refresh token (#10)
Browse files Browse the repository at this point in the history
* 🚧 토큰 갱신 버그 수정

* 🐛 쿠키 삭제 로직 수정
  • Loading branch information
RetepMil authored Dec 20, 2023
1 parent 31e13e3 commit 5e15831
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 37 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
- "develop"
- "main"
- "infra/**"
- "modify/**"
pull_request:
branches:
- "develop"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import jakarta.validation.Valid
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import retepmil.personal.dailysteady.common.dto.BaseResponseDto
import retepmil.personal.dailysteady.common.dto.DataResponseDto
import retepmil.personal.dailysteady.common.security.jwt.JwtTokenProvider
import retepmil.personal.dailysteady.members.dto.MemberCreateRequestDto
import retepmil.personal.dailysteady.members.dto.MemberLoginRequestDto
import retepmil.personal.dailysteady.members.dto.MemberLoginResponseDto
import retepmil.personal.dailysteady.members.service.MemberService

@RestController
class AuthController(
private val memberService: MemberService,
private val jwtTokenProvider: JwtTokenProvider,
) {
private val logger: Logger = LoggerFactory.getLogger(AuthController::class.java)

Expand Down Expand Up @@ -56,28 +56,4 @@ class AuthController(
return DataResponseDto(200, responseDto)
}

@PatchMapping("/token")
fun renewToken(
@CookieValue("refreshToken") refreshToken: String,
@CookieValue("x-access-token") accessToken: String,
response: HttpServletResponse,
): DataResponseDto<MemberLoginResponseDto> {
logger.debug("SecurityController -> renewToken 함수 진입")

logger.debug("{} ||", refreshToken)
logger.debug("{} ||", accessToken)

val responseDto = jwtTokenProvider.renewToken(accessToken, refreshToken)

// 쿠키에 Access Token 주입
val accessTokenCookie = JwtTokenProvider.generateAccessTokenCookie(responseDto.tokenInfo.accessToken)
response.addHeader("Set-Cookie", accessTokenCookie.toString())

// 쿠키에 Refresh Token 주입
val refreshTokenCookie = JwtTokenProvider.generateRefreshTokenCookie(responseDto.tokenInfo.refreshToken)
response.addHeader("Set-Cookie", refreshTokenCookie.toString())

return DataResponseDto(200, responseDto)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package retepmil.personal.dailysteady.common.security.exception

class RefreshTokenExpiredException : Exception("Refresh Token이 만료되었습니다.")
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package retepmil.personal.dailysteady.common.security.exception

class RefreshTokenNotFoundException : Exception("Refresh Token 값이 조회되지 않습니다")
class RefreshTokenNotFoundException : Exception("Refresh Token 값이 조회되지 않습니다.")
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import jakarta.servlet.ServletException
import jakarta.servlet.ServletRequest
import jakarta.servlet.ServletResponse
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.util.StringUtils
import org.springframework.web.filter.GenericFilterBean
import retepmil.personal.dailysteady.common.security.exception.InvalidTokenException
import retepmil.personal.dailysteady.common.security.exception.RefreshTokenExpiredException
import retepmil.personal.dailysteady.common.security.jwt.JwtCode
import retepmil.personal.dailysteady.common.security.jwt.JwtTokenProvider

Expand All @@ -17,21 +19,42 @@ class JwtAuthenticationFilter(
) : GenericFilterBean() {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain?) {
val httpRequest = request as HttpServletRequest
val httpResponse = response as HttpServletResponse

if (httpRequest.requestURI == "/health") {
chain?.doFilter(request, response)
return
}

logger.debug("JWT 필터 로직 실행")
val token = resolveAccessToken(httpRequest)
if (token != null) when (jwtTokenProvider.validateToken(token)) {
val accessToken = resolveAccessToken(httpRequest)
if (accessToken != null) when (jwtTokenProvider.validateToken(accessToken)) {
JwtCode.ACCESS -> {
val authentication = jwtTokenProvider.getAuthentication(token)
val authentication = jwtTokenProvider.getAuthentication(accessToken)
SecurityContextHolder.getContext().authentication = authentication
request.setAttribute("authentication", authentication)
}
JwtCode.EXPIRED -> throw InvalidTokenException("토큰이 만료되었습니다")
JwtCode.EXPIRED -> {
logger.debug("액세스 토큰이 만료되었습니다. 갱신을 시도합니다.")
val refreshToken = request.cookies.find { it.name == "refreshToken" }?.value
?: throw InvalidTokenException("refresh token이 존재하지 않습니다")

// 액세스 토큰 갱신 작업을 진행
try {
logger.debug("토큰 쌍 갱신 시도")
val dto = jwtTokenProvider.renewToken(accessToken, refreshToken)
httpResponse.addHeader("Set-Cookie",
JwtTokenProvider.generateAccessTokenCookie(dto.tokenInfo.accessToken).toString())
httpResponse.addHeader("Set-Cookie",
JwtTokenProvider.generateRefreshTokenCookie(dto.tokenInfo.refreshToken).toString())
} catch (e: RefreshTokenExpiredException) {
logger.debug("토큰 쌍 삭제 시도")
request.cookies.forEach { response.addCookie(it.apply { maxAge = 0 }) }
} catch (e: Exception) {
throw InvalidTokenException("토큰 갱신 단계에서 오류가 발생했습니다")
}

}
JwtCode.SECURITY_ERROR -> throw InvalidTokenException("토큰에 보안 관련 문제가 있습니다")
JwtCode.MALFORMED -> throw InvalidTokenException("토큰에 문제가 있습니다")
JwtCode.UNSUPPORTED -> throw InvalidTokenException("시스템에서 허용하는 토큰 스펙이 아닙니다")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import retepmil.personal.dailysteady.common.security.exception.InvalidTokenException
import retepmil.personal.dailysteady.common.security.exception.RefreshTokenExpiredException
import retepmil.personal.dailysteady.common.security.exception.RefreshTokenNotFoundException
import retepmil.personal.dailysteady.common.security.repository.MemberRoleRepository
import retepmil.personal.dailysteady.common.security.repository.RefreshTokenRepository
Expand Down Expand Up @@ -62,10 +62,8 @@ class JwtTokenProvider(
fun renewToken(accessToken: String, refreshToken: String): MemberLoginResponseDto {
logger.debug("Token Renew 로직 시작")

if (validateToken(accessToken) != JwtCode.EXPIRED)
throw InvalidTokenException("Access Token 값이 EXPIRED 상태가 아닙니다")
if (validateToken(refreshToken) != JwtCode.EXPIRED)
throw InvalidTokenException("Refresh Token 값이 EXPIRED 상태가 아닙니다")
if (validateToken(refreshToken) == JwtCode.EXPIRED)
throw RefreshTokenExpiredException()

val email = getClaims(accessToken).subject
val member = memberRepository.findByEmail(email) ?: throw MemberNotFoundException()
Expand Down Expand Up @@ -171,5 +169,15 @@ class JwtTokenProvider(
.secure(true)
.sameSite("None")
.build()

fun generateRefreshTokenDeleteCookie() = ResponseCookie.from("refreshToken")
.value("")
.maxAge(0)
.build()

fun generateAccessTokenDeleteCookie() = ResponseCookie.from("x-access-token")
.value("")
.maxAge(0)
.build()
}
}

0 comments on commit 5e15831

Please sign in to comment.