Skip to content

Commit

Permalink
Merge pull request #58 from PSR-Co/feat/#56-reissueToken
Browse files Browse the repository at this point in the history
[feat] 토큰 재발급 API
  • Loading branch information
chaerlo127 authored Aug 5, 2023
2 parents 6dcae29 + 237a287 commit dd2fcbe
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class WebSecurityConfig(
c.requestMatchers("/users/signup").permitAll()
c.requestMatchers("/users/nickname").permitAll()
c.requestMatchers("/users/eid").permitAll()
c.requestMatchers("/users/reissue").permitAll()
c.anyRequest().authenticated()
}
.apply(JwtSecurityConfig(jwtUtils, redisTemplate))
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/com/psr/psr/global/jwt/dto/TokenDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.psr.psr.global.jwt.dto

import org.jetbrains.annotations.NotNull

data class TokenDto(
@field:NotNull
var accessToken: String,
@field:NotNull
var refreshToken: String,
val type: String ?= null
)
5 changes: 0 additions & 5 deletions src/main/kotlin/com/psr/psr/global/jwt/dto/TokenRes.kt

This file was deleted.

13 changes: 10 additions & 3 deletions src/main/kotlin/com/psr/psr/global/jwt/utils/JwtUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.psr.psr.global.Constant.JWT.JWT.BEARER_PREFIX
import com.psr.psr.global.exception.BaseException
import com.psr.psr.global.exception.BaseResponseCode
import com.psr.psr.global.jwt.UserDetailsServiceImpl
import com.psr.psr.global.jwt.dto.TokenRes
import com.psr.psr.global.jwt.dto.TokenDto
import com.psr.psr.user.entity.Type
import io.jsonwebtoken.*
import io.jsonwebtoken.io.Decoders
Expand Down Expand Up @@ -43,7 +43,7 @@ class JwtUtils(
/**
* 토큰 생성
*/
fun createToken(authentication: Authentication, type: Type): TokenRes {
fun createToken(authentication: Authentication, type: Type): TokenDto {
val authorities = authentication.authorities.stream()
.map { obj: GrantedAuthority -> obj.authority }
.collect(Collectors.joining(","))
Expand All @@ -62,7 +62,7 @@ class JwtUtils(
.compact()
redisTemplate.opsForValue().set(authentication.name, refreshToken, Duration.ofMillis(REFRESH_TOKEN_EXPIRE_TIME))

return TokenRes(BEARER_PREFIX + accessToken, BEARER_PREFIX + refreshToken, type.value)
return TokenDto(BEARER_PREFIX + accessToken, BEARER_PREFIX + refreshToken, type.value)
}

/**
Expand Down Expand Up @@ -133,6 +133,13 @@ class JwtUtils(
if(redisTemplate.opsForValue().get(userId.toString()) != null) redisTemplate.delete(userId.toString())
}

/**
* check Token in Redis DB
*/
fun validateRefreshToken(userId: Long, refreshToken: String) {
val redisToken = redisTemplate.opsForValue().get(userId.toString())
if(redisToken == null || redisToken != refreshToken) throw BaseException(BaseResponseCode.INVALID_TOKEN)
}


}
15 changes: 12 additions & 3 deletions src/main/kotlin/com/psr/psr/user/controller/UserController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.psr.psr.global.Constant.USER_STATUS.USER_STATUS.LOGOUT
import com.psr.psr.global.dto.BaseResponse
import com.psr.psr.global.exception.BaseResponseCode
import com.psr.psr.global.jwt.UserAccount
import com.psr.psr.global.jwt.dto.TokenRes
import com.psr.psr.global.jwt.dto.TokenDto
import com.psr.psr.user.dto.*
import com.psr.psr.user.service.UserService
import jakarta.servlet.http.HttpServletRequest
Expand All @@ -23,7 +23,7 @@ class UserController(
*/
@PostMapping("/signup")
@ResponseBody
fun signUp (@RequestBody @Validated signUpReq: SignUpReq) : BaseResponse<TokenRes>{
fun signUp (@RequestBody @Validated signUpReq: SignUpReq) : BaseResponse<TokenDto>{
return BaseResponse(userService.signUp(signUpReq))
}

Expand All @@ -32,7 +32,7 @@ class UserController(
*/
@PostMapping("/login")
@ResponseBody
fun login (@RequestBody @Validated loginReq: LoginReq) : BaseResponse<TokenRes>{
fun login (@RequestBody @Validated loginReq: LoginReq) : BaseResponse<TokenDto>{
return BaseResponse(userService.login(loginReq))
}

Expand Down Expand Up @@ -105,5 +105,14 @@ class UserController(
return BaseResponse(userService.getMyPageInfo(userAccount.getUser()))
}

/**
* 토큰 재발급
*/
@PostMapping("/reissue")
@ResponseBody
fun reissueToken(@RequestBody @Validated tokenDto: TokenDto) : BaseResponse<TokenDto>{
return BaseResponse(userService.reissueToken(tokenDto))
}


}
12 changes: 8 additions & 4 deletions src/main/kotlin/com/psr/psr/user/dto/assembler/UserAssembler.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.psr.psr.user.dto.assembler

import com.psr.psr.user.dto.MyPageInfoRes
import com.psr.psr.user.dto.ProfileRes
import com.psr.psr.user.dto.SignUpReq
import com.psr.psr.user.dto.UserEidReq
import com.psr.psr.global.Constant
import com.psr.psr.global.jwt.dto.TokenDto
import com.psr.psr.user.dto.*
import com.psr.psr.user.dto.eidReq.Business
import com.psr.psr.user.dto.eidReq.BusinessListReq
import com.psr.psr.user.entity.*
Expand Down Expand Up @@ -63,4 +62,9 @@ class UserAssembler {
fun toProfileRes(user: User) : ProfileRes {
return ProfileRes(user.email, user.imgKey)
}

fun toTokenDto(tokenDto: TokenDto) {
tokenDto.accessToken.replace(Constant.JWT.BEARER_PREFIX, "").also { tokenDto.accessToken = it }
tokenDto.refreshToken.replace(Constant.JWT.BEARER_PREFIX, "").also { tokenDto.refreshToken = it }
}
}
27 changes: 22 additions & 5 deletions src/main/kotlin/com/psr/psr/user/service/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.psr.psr.global.Constant
import com.psr.psr.global.Constant.USER_EID.USER_EID.EID_URL
import com.psr.psr.global.Constant.USER_EID.USER_EID.PAY_STATUS
import com.psr.psr.global.Constant.USER_STATUS.USER_STATUS.ACTIVE_STATUS
import com.psr.psr.global.exception.BaseException
import com.psr.psr.global.exception.BaseResponseCode.*
import com.psr.psr.global.jwt.dto.TokenRes
import com.psr.psr.global.jwt.dto.TokenDto
import com.psr.psr.global.jwt.utils.JwtUtils
import com.psr.psr.user.dto.*
import com.psr.psr.user.dto.assembler.UserAssembler
import com.psr.psr.user.dto.eidReq.BusinessListRes
import com.psr.psr.user.entity.BusinessInfo
import com.psr.psr.user.entity.Type
import com.psr.psr.user.entity.User
import com.psr.psr.user.repository.BusinessInfoRepository
Expand Down Expand Up @@ -47,7 +47,7 @@ class UserService(
) {
// 회원가입
@Transactional
fun signUp(signUpReq: SignUpReq): TokenRes {
fun signUp(signUpReq: SignUpReq): TokenDto {
val categoryCheck = signUpReq.interestList.stream().map { i -> i.checkInterestCategory() }.collect(Collectors.toList()).groupingBy { it }.eachCount().any { it.value > 1 }
if(categoryCheck) throw BaseException(INVALID_USER_INTEREST_COUNT)
// category 의 사이즈 확인
Expand Down Expand Up @@ -80,7 +80,7 @@ class UserService(
}

// 로그인
fun login(loginReq: LoginReq) : TokenRes{
fun login(loginReq: LoginReq) : TokenDto{
val user = userRepository.findByEmail(loginReq.email).orElseThrow{BaseException(NOT_EXIST_EMAIL)}
if(!passwordEncoder.matches(loginReq.password, user.password)) throw BaseException(INVALID_PASSWORD)
return createToken(user, loginReq.password)
Expand All @@ -92,7 +92,7 @@ class UserService(
}

// token 생성 extract method
private fun createToken(user: User, password: String): TokenRes {
private fun createToken(user: User, password: String): TokenDto {
val authenticationToken = UsernamePasswordAuthenticationToken(user.id.toString(), password)
val authentication = authenticationManagerBuilder.`object`.authenticate(authenticationToken)
return jwtUtils.createToken(authentication, user.type)
Expand Down Expand Up @@ -163,4 +163,21 @@ class UserService(
fun getMyPageInfo(user: User): MyPageInfoRes {
return userAssembler.toMyPageInfoRes(user)
}

// 토큰 재발급
fun reissueToken(tokenDto: TokenDto): TokenDto {
// bearer String replace blank
userAssembler.toTokenDto(tokenDto)
// refresh token 검증
jwtUtils.validateToken(tokenDto.refreshToken)
// accessToken 내 사용자 정보
val authentication = jwtUtils.getAuthentication(tokenDto.accessToken)
val user = userRepository.findByIdAndStatus(authentication.name.toLong(), ACTIVE_STATUS) ?: throw BaseException(NOT_FOUND_USER)
// refreshToken이 redis 내 토큰과 같은지 확인
jwtUtils.validateRefreshToken(user.id!!, tokenDto.refreshToken)
// redis 내 refreshToken 삭제
jwtUtils.deleteRefreshToken(user.id!!)
// token 생성
return jwtUtils.createToken(authentication, user.type)
}
}

0 comments on commit dd2fcbe

Please sign in to comment.