Skip to content

Commit

Permalink
Merge pull request #66 from TinU-Official/issue63/refresh-token-logic…
Browse files Browse the repository at this point in the history
…-feat

[issue63] [Feat] RefreshToken logic 완성
  • Loading branch information
programofktw authored Dec 17, 2024
2 parents 4e7e1e1 + beb814d commit de7aa73
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ package com.tinuproject.tinu.domain.exception.token

import com.tinuproject.tinu.domain.exception.base.BaseException

class InvalidedToken(
class InvalidedTokenException(

):BaseException(tokenErrorCode=TokenErrorCode.TOKEN_INVALIDED) {}
8 changes: 8 additions & 0 deletions src/main/kotlin/com/tinuproject/tinu/domain/token/Tokens.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.tinuproject.tinu.domain.token

class Tokens(
val accessToken : String,
val refreshToken : String
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.tinuproject.tinu.domain.token.refreshtoken

import com.tinuproject.tinu.domain.exception.token.InvalidedTokenException
import com.tinuproject.tinu.domain.exception.token.NotFoundTokenException
import com.tinuproject.tinu.domain.token.Tokens
import com.tinuproject.tinu.domain.token.refreshtoken.service.RefreshTokenService
import com.tinuproject.tinu.web.CookieGenerator
import jakarta.servlet.http.HttpServletResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping

@Controller
@RequestMapping("api/token")
class RefreshTokenController(
private val refreshTokenService : RefreshTokenService,

@Value("\${cookie.token.access-token}")
private val accessTokenKey : String,

@Value("\${cookie.token.refresh-token}")
private val refreshTokenkey : String
) {
var log : Logger = LoggerFactory.getLogger(this::class.java)


@GetMapping("/generate")
fun generateAccessToken(httpServletResponse: HttpServletResponse, @CookieValue(name = "RefreshToken") refreshToken : String?): ResponseEntity<Map<String, Any>> {
var tokens : Tokens
log.info("AccessToken 갱신 시도")
if(refreshToken==null){
throw NotFoundTokenException()
}
try{
tokens = refreshTokenService.ReissueAccessTokenByRefreshToken(refreshToken)
}catch (e : InvalidedTokenException){
throw e
}

httpServletResponse.addCookie(CookieGenerator.createCookies(accessTokenKey,tokens.accessToken))
httpServletResponse.addCookie(CookieGenerator.createCookies(refreshTokenkey, tokens.refreshToken))
var body : MutableMap<String, Any> = mutableMapOf()

body.put("Tokens",tokens)

var responseEntity : ResponseEntity<Map<String, Any>> = ResponseEntity.ok().body(body)
return responseEntity
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.tinuproject.tinu.security
package com.tinuproject.tinu.domain.token.refreshtoken.repository

import com.tinuproject.tinu.domain.entity.RefreshToken
import jakarta.persistence.ManyToOne
Expand All @@ -8,7 +8,6 @@ import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
import java.util.*

@Repository
interface RefreshTokenRepository:CrudRepository<RefreshToken, Long> {

fun findByUserId(userId : UUID) : RefreshToken
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.tinuproject.tinu.domain.token.refreshtoken.service

import com.tinuproject.tinu.domain.token.Tokens
import org.springframework.stereotype.Service


interface RefreshTokenService {
fun ReissueAccessTokenByRefreshToken(refreshToken : String) : Tokens
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.tinuproject.tinu.domain.token.refreshtoken.service

import com.tinuproject.tinu.domain.entity.RefreshToken
import com.tinuproject.tinu.domain.exception.token.InvalidedTokenException
import com.tinuproject.tinu.domain.token.Tokens
import com.tinuproject.tinu.domain.token.refreshtoken.repository.RefreshTokenRepository
import com.tinuproject.tinu.security.jwt.JwtUtil
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.security.SignatureException
import java.util.*

@Service
class RefreshTokenServiceImpl(
@Value("\${jwt.refresh-token.expiration-time}")
private val REFRESH_TOKEN_EXPIRATION_TIME: Long, // 리프레쉬 토큰 유효기간

@Value("\${jwt.access-token.expiration-time}")
private val ACCESS_TOKEN_EXPIRATION_TIME: Long, // 액세스 토큰 유효기간

private val refreshTokenRepository: RefreshTokenRepository,
private val jwtUtil : JwtUtil,
):RefreshTokenService {
var log : Logger = LoggerFactory.getLogger(this::class.java)

override fun ReissueAccessTokenByRefreshToken(refreshToken: String): Tokens {
try{
jwtUtil.validateToken(refreshToken)
}catch (e : SignatureException){
throw InvalidedTokenException()
}

val userId :UUID = UUID.fromString(jwtUtil.getUserIdFromToken(refreshToken))

//리프레쉬 토큰 삭제
refreshTokenRepository.deleteByUserId(userId)

//리프레쉬 토큰 재발행.
val token = jwtUtil.generateRefreshToken(userId,REFRESH_TOKEN_EXPIRATION_TIME)

val newRefreshToken = RefreshToken(userId = userId, token = token)

//리프레쉬 토큰 저장
refreshTokenRepository.save(newRefreshToken)

//AccesToken 재발행.
val accessToken : String = jwtUtil.generateAccessToken(userId, ACCESS_TOKEN_EXPIRATION_TIME)

return Tokens(accessToken=accessToken, refreshToken = refreshToken)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class SecurityConfig(
return WebSecurityCustomizer { web: WebSecurity ->
//로그인이 아예 안되어 있어도 괜찮은 api
//해당 ""에 API 추가시 해당 API는 필터를 거치지 않음.
// web.ignoring().requestMatchers("")
web.ignoring().requestMatchers("/api/token/**")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class JwtUtil {
}catch(e : SignatureException){
log.warn("Claim이 유효하지 않은 토큰입니다.{}",e.message)
//TODO(유효하지 않는 토큰 처리")
throw Exception()
throw e
}catch (e : Exception){
log.warn("토큰과 관련한 예기치 못한 에러가 발생했습니다.")
//TODO(예상치 못한 오류 에러로 처리)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.tinuproject.tinu.domain.entity.RefreshToken
import com.tinuproject.tinu.domain.entity.SocialMember
import com.tinuproject.tinu.domain.enum.Social
import com.tinuproject.tinu.domain.socialmember.repository.SocialMemberRepository
import com.tinuproject.tinu.security.RefreshTokenRepository
import com.tinuproject.tinu.domain.token.refreshtoken.repository.RefreshTokenRepository
import com.tinuproject.tinu.security.jwt.JwtUtil
import com.tinuproject.tinu.security.oauth2.dto.KakaoUserInfo
import com.tinuproject.tinu.security.oauth2.dto.NaverUserInfo
Expand All @@ -31,7 +31,7 @@ class OAuthLoginSuccessHandler(

private val jwtUtil: JwtUtil,

private val userRepository: SocialMemberRepository ,
private val userRepository: SocialMemberRepository,

private val refreshTokenRepository: RefreshTokenRepository,

Expand Down
17 changes: 17 additions & 0 deletions src/main/kotlin/com/tinuproject/tinu/web/CookieGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tinuproject.tinu.web

import jakarta.servlet.http.Cookie

class CookieGenerator {
companion object{
fun createCookies(key : String, value : String) : Cookie {
val cookie = Cookie(key, value)
cookie.path = "/"
cookie.isHttpOnly = false
cookie.secure = false
cookie.maxAge = 3600

return cookie
}
}
}

0 comments on commit de7aa73

Please sign in to comment.