티스토리 뷰

 

https://ekeprl.tistory.com/63

 

[Spring Security - JWT] (1) : SecurityConfig 설정

https://ekeprl.tistory.com/62 [Spring Security] 세션 기반 vs JWT 기반https://ekeprl.tistory.com/30 Spring Security (1)Spring boot : 3.1Spring Security6Kotlin Spring security의 방식에 대해선 다루지않고, 어떻게 작성했는지를 다루

ekeprl.tistory.com

이전 포스팅을 통해 JWT 기반 인증을 위한 SecurityConfig 설정을 알아보았다.

이어서 이번 포스팅은 JWT 토큰의 생성과 검증을 담당하는 JwtUtil을 작성해보려 한다.

 

1. Build.gradle.kts

dependencies {

    // JWT
    implementation("io.jsonwebtoken:jjwt-api:0.12.6")
    runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")
    runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6")
    
    }

 

가장 먼저,  JWT 토큰을 생성하고 파싱 하기 위해 jjwt 라이브러리를 Build.gradle.kts에 추가한다.

 

2. application-dev.yml

jwt:
  secret: your secret key
  access-expiration: 1800000
  refresh-expiration: 604800000

 

이후 토큰서명에 사용할 secret키

토큰의 만료시간 expiration을 작성해줬다.

 

3. JwtUtil

@Component
class JwtUtil(
    @Value("\${jwt.secret}") private val secret: String,
    @Value("\${jwt.access-expiration}") private val accessExpiration: Long,
    @Value("\${jwt.refresh-expiration}") private val refreshExpiration: Long
) {
    private val secretKey: SecretKey by lazy {
        Keys.hmacShaKeyFor(secret.toByteArray())
    }

    // Access Token 생성
    fun generateAccessToken(userId: String, email: String, role: String): String {
        return Jwts.builder()
            .subject(userId)
            .claim("email", email)
            .claim("role", role)
            .issuedAt(Date())
            .expiration(Date(System.currentTimeMillis() + accessExpiration))
            .signWith(secretKey)
            .compact()
    }

    // Refresh Token 생성
    fun generateRefreshToken(userId: String): String {
        return Jwts.builder()
            .subject(userId)
            .issuedAt(Date())
            .expiration(Date(System.currentTimeMillis() + refreshExpiration))
            .signWith(secretKey)
            .compact()
    }

    // 토큰에서 userId 추출
    fun getUserId(token: String): String {
        return getClaims(token).subject
    }

    // 토큰 유효성 검증
    fun validateToken(token: String): Boolean {
        return try {
            getClaims(token)
            true
        } catch (e: Exception) {
            false
        }
    }

    // 토큰에서 email 추출
    fun getEmail(token: String): String {
        return getClaims(token)["email"] as String
    }

    // 토큰에서 role 추출
    fun getRole(token: String): String {
        return getClaims(token)["role"] as String
    }

    private fun getClaims(token: String) =
        Jwts.parser()
            .verifyWith(secretKey)
            .build()
            .parseSignedClaims(token)
            .payload
}

 

이제 Jwt토큰의 생성, 추출, 검증을 담당하는 JwtUtil에 대해 설명해보려 한다.

 

(1) SecretKey

private val secretKey: SecretKey by lazy {
    Keys.hmacShaKeyFor(secret.toByteArray())
}

가장 먼저 yml에 작성한 secertkey문자열로 HMAC-SHA키를 생성한다.

lazy : 최초 호출 시 한 번만 생성하기 위해 작성

 

(2) 토큰 생성

fun generateAccessToken()
fun generateRefreshToken()

generateAccessToken() 함수는 userId를 subject로 / email, role을 claim으로 담아 Access Token을 생성한다.

generateRefreshToken() 함수는 userId만 따로 담아 Refresh Token을 생성한다.

 

(3) 토큰 파싱

fun getUserId()
fun getEmail()
fun getRole()
private fun getClaims()

위의 세 가지 함수 getUserId() / getEmail() / getRole()은 getClaim() 함수를 통해 각 정보를 추출한다.

getClaim() 함수는 토큰을 파싱해 Claim을 반환하는 공통 메서드로 작성했다.

 

(4) 유효성 검증

fun validateToken(token: String): Boolean {
    return try {
        getClaims(token)
        true
    } catch (e: Exception) {
        false
    }
}

validateToken() 함수를 이용해 파싱 성공여부로 유효성을 판단하고, 만료 or 변조를 감지하면 false를 반환한다.

 

이상으로 JwtUtil 작성을 알아보았습니다.

 

다음 포스팅은 요청마다 JWT 토큰을 검증하는 JwtFilter를 작성해보려 합니다.

감사합니다.

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/08   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함