Skip to content

Commit

Permalink
Merge pull request #132 from GSM-MSG/131-jwt-provider-oauth-gauth
Browse files Browse the repository at this point in the history
131 jwt provider oauth gauth
  • Loading branch information
esperar authored Apr 6, 2023
2 parents 12bb380 + bcc0fed commit 6e6b0da
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,24 @@ class RefreshService(
private val jwtTokenProvider: JwtTokenProvider,
private val refreshTokenRepository: RefreshTokenRepository
) {
fun execute(refreshToken: String): RefreshResponseDto {
val refreshToken = jwtTokenProvider.parseToken(refreshToken) ?: throw InvalidRefreshTokenException()
fun execute(requestToken: String): RefreshResponseDto {
val refreshToken = jwtTokenProvider.parseToken(requestToken) ?: throw InvalidRefreshTokenException()
val email = jwtTokenProvider.exactEmailFromRefreshToken(refreshToken)
val existingRefreshToken = refreshTokenRepository.findByToken(refreshToken) ?: throw ExpiredRefreshTokenException()

val existingRefreshToken = refreshTokenRepository.findByToken(refreshToken)
?: throw ExpiredRefreshTokenException()

if (existingRefreshToken.token != refreshToken)
throw InvalidRefreshTokenException()
val access = jwtTokenProvider.generateAccessToken(email)
val refresh = jwtTokenProvider.generateRefreshToken(email)
val expiresAt = jwtTokenProvider.accessExpiredTime

val (access, refresh) = jwtTokenProvider.run {
generateAccessToken(email) to generateRefreshToken(email)}

val newRefreshToken = RefreshToken(
userId = existingRefreshToken.userId,
token = refresh,
)
refreshTokenRepository.save(newRefreshToken)
return RefreshResponseDto(access, refresh, expiresAt)
return RefreshResponseDto(access, refresh, jwtTokenProvider.accessExpiredTime)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ class SignInService(
) {
fun execute(dto: SigninRequestDto): SigninResponseDto {
val user: User = userRepository.findByEmail(dto.email) ?: throw UserNotFoundException()

if (!passwordEncoder.matches(dto.password, user.password))
throw PasswordMismatchException()

if(user.state != UserState.CREATED)
throw UserIsPendingException()
val access = jwtTokenProvider.generateAccessToken(dto.email)
val refresh = jwtTokenProvider.generateRefreshToken(dto.email)

val (access, refresh) = jwtTokenProvider.run {
generateAccessToken(dto.email) to generateRefreshToken(dto.email)}

val expiresAt = jwtTokenProvider.accessExpiredTime

refreshTokenRepository.save(RefreshToken(user.id, refresh))
return SigninResponseDto(access, refresh, expiresAt)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,30 @@ import com.msg.gauth.domain.user.exception.UserNotFoundException
import com.msg.gauth.domain.user.repository.UserRepository
import com.msg.gauth.global.annotation.service.TransactionalService
import com.msg.gauth.global.security.jwt.JwtTokenProvider
import com.msg.gauth.global.security.jwt.OauthTokenProvider
import org.springframework.stereotype.Service

@TransactionalService
class OauthRefreshService(
private val tokenRepository: OauthRefreshTokenRepository,
private val tokenProvider: JwtTokenProvider,
private val oauthTokenProvider: OauthTokenProvider,
private val userRepository: UserRepository,
){
fun execute(refreshToken: String): UserTokenResponseDto{
val refreshToken = tokenProvider.parseToken(refreshToken) ?: throw InvalidRefreshTokenException()
val email = tokenProvider.exactEmailFromOauthRefreshToken(refreshToken)
fun execute(requestToken: String): UserTokenResponseDto{
val refreshToken = oauthTokenProvider.parseToken(requestToken) ?: throw InvalidRefreshTokenException()

val (email, clientId) = oauthTokenProvider.run {
exactEmailFromOauthRefreshToken(refreshToken) to exactClientIdFromOauthRefreshToken(refreshToken)
}
val user = userRepository.findByEmail(email) ?: throw UserNotFoundException()
if(!tokenRepository.existsById(user.id))
throw ExpiredRefreshTokenException()
val clientId = tokenProvider.exactClientIdFromOauthRefreshToken(refreshToken)
val access = tokenProvider.generateOauthAccessToken(email, clientId)
val refresh = tokenProvider.generateOauthRefreshToken(email, clientId)
val newRefreshToken = OauthRefreshToken(
userId = user.id,
token = refresh,
)
if (!tokenRepository.existsById(user.id)) throw ExpiredRefreshTokenException()

val (access, refresh) = oauthTokenProvider.run {
generateOauthAccessToken(email, clientId) to generateOauthRefreshToken(email, clientId)
}
val newRefreshToken = OauthRefreshToken(user.id, refresh)
tokenRepository.save(newRefreshToken)

return UserTokenResponseDto(access, refresh)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import com.msg.gauth.domain.user.exception.UserNotFoundException
import com.msg.gauth.domain.user.repository.UserRepository
import com.msg.gauth.global.annotation.service.ReadOnlyService
import com.msg.gauth.global.security.jwt.JwtTokenProvider
import com.msg.gauth.global.security.jwt.OauthTokenProvider
import org.springframework.security.crypto.password.PasswordEncoder

@ReadOnlyService
class OauthTokenService(
private val clientRepository: ClientRepository,
private val userRepository: UserRepository,
private val tokenProvider: JwtTokenProvider,
private val oauthTokenProvider: OauthTokenProvider,
private val refreshTokenRepository: OauthRefreshTokenRepository,
private val oauthCodeRepository: OauthCodeRepository
){
Expand All @@ -43,8 +44,8 @@ class OauthTokenService(
client: Client,
user: User
): UserTokenResponseDto {
val accessToken = tokenProvider.generateOauthAccessToken(email, client.clientId)
val refreshToken = tokenProvider.generateOauthRefreshToken(email, client.clientId)
val (accessToken, refreshToken) = oauthTokenProvider.run {
generateOauthAccessToken(email, client.clientId) to generateOauthRefreshToken(email, client.clientId)}
refreshTokenRepository.save(OauthRefreshToken(user.id, refreshToken))
return UserTokenResponseDto(
accessToken = accessToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.msg.gauth.global.security.jwt

import com.msg.gauth.domain.auth.repository.RefreshTokenRepository
import com.msg.gauth.domain.oauth.repository.OauthRefreshTokenRepository
import com.msg.gauth.global.security.auth.AuthDetailsService
import com.msg.gauth.global.security.exception.ExpiredTokenException
import com.msg.gauth.global.security.exception.InvalidTokenException
Expand Down Expand Up @@ -37,22 +39,6 @@ class JwtTokenProvider(
fun generateRefreshToken(email: String): String =
generateToken(email, REFRESH_TYPE, jwtProperties.refreshSecret, REFRESH_EXP)

fun generateOauthAccessToken(email: String, clientId: String): String =
generateOauthToken(email, ACCESS_TYPE, clientId, jwtProperties.oauthSecret, ACCESS_EXP)

fun generateOauthRefreshToken(email: String, clientId: String): String =
generateOauthToken(email, REFRESH_TYPE, clientId, jwtProperties.oauthSecret, REFRESH_EXP)


private fun generateOauthToken(sub: String, type: String, clientId: String, secret: Key, exp: Long): String =
Jwts.builder()
.signWith(secret, SignatureAlgorithm.HS256)
.setSubject(sub)
.claim("clientId", clientId)
.claim("type", type)
.setIssuedAt(Date())
.setExpiration(Date(System.currentTimeMillis() + exp * 1000))
.compact()

fun resolveToken(req: HttpServletRequest): String? {
val token = req.getHeader("Authorization") ?: return null
Expand All @@ -63,11 +49,6 @@ class JwtTokenProvider(
return getTokenSubject(refresh, jwtProperties.refreshSecret)
}

fun exactEmailFromOauthRefreshToken(refresh: String): String =
getTokenSubject(refresh, jwtProperties.oauthSecret)

fun exactClientIdFromOauthRefreshToken(refresh: String): String =
getTokenBody(refresh, jwtProperties.oauthSecret)["clientId"].toString()

fun authentication(token: String): Authentication {
val userDetails = authDetailsService.loadUserByUsername(getTokenSubject(token, jwtProperties.accessSecret))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.msg.gauth.global.security.jwt

import com.msg.gauth.global.security.auth.AuthDetailsService
import com.msg.gauth.global.security.exception.ExpiredTokenException
import com.msg.gauth.global.security.exception.InvalidTokenException
import io.jsonwebtoken.Claims
import io.jsonwebtoken.ExpiredJwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import org.springframework.stereotype.Component
import java.security.Key
import java.util.*

@Component
class OauthTokenProvider(
private val jwtProperties: JwtProperties
) {

companion object {
const val OAUTH_ACCESS_TYPE = "access"
const val OAUTH_REFRESH_TYPE = "refresh"
const val OAUTH_ACCESS_EXP = 60L * 15 // 15 min
const val OAUTH_REFRESH_EXP = 60L * 60 * 24 * 7 // 1 weeks
const val TOKEN_PREFIX = "Bearer "
}

fun generateOauthAccessToken(email: String, clientId: String): String =
generateOauthToken(email,
OAUTH_ACCESS_TYPE, clientId, jwtProperties.oauthSecret,
OAUTH_ACCESS_EXP
)

fun generateOauthRefreshToken(email: String, clientId: String): String =
generateOauthToken(email,
OAUTH_REFRESH_TYPE, clientId, jwtProperties.oauthSecret,
OAUTH_REFRESH_EXP
)

private fun generateOauthToken(sub: String, type: String, clientId: String, secret: Key, exp: Long): String =
Jwts.builder()
.signWith(secret, SignatureAlgorithm.HS256)
.setSubject(sub)
.claim("clientId", clientId)
.claim("type", type)
.setIssuedAt(Date())
.setExpiration(Date(System.currentTimeMillis() + exp * 1000))
.compact()

fun parseToken(token: String): String? =
if (token.startsWith(TOKEN_PREFIX)) token.replace(TOKEN_PREFIX, "") else null

fun exactEmailFromOauthRefreshToken(refresh: String): String =
getTokenSubject(refresh, jwtProperties.oauthSecret)

fun exactClientIdFromOauthRefreshToken(refresh: String): String =
getTokenBody(refresh, jwtProperties.oauthSecret)["clientId"].toString()

private fun getTokenBody(token: String, secret: Key): Claims {
return try {
Jwts.parserBuilder()
.setSigningKey(secret)
.build()
.parseClaimsJws(token)
.body
} catch (e: ExpiredJwtException) {
throw ExpiredTokenException()
} catch (e: Exception) {
throw InvalidTokenException()
}
}

private fun getTokenSubject(token: String, secret: Key): String =
getTokenBody(token, secret).subject

}

0 comments on commit 6e6b0da

Please sign in to comment.