20240116 (화) 코틀린 + 스프링 심화과정 개인공부(화~금)

2024. 1. 16. 20:02TIL

심화과정은 인증/인가 쪽을 주로 다루는데

제출은 이전에 했던 TodoApp 을 만든것에다가 인증/인가를 더한 것을 제출해야한다.

하지만 나는 TodoApp을 만들시에 인증/인가를 생각안하고 따로 패스워드, 유저이름 등을 만들어놓았기에

오늘 하루는 일단 기존 TodoApp에서 인증/인가가 추가되었을 때 없어져야할 코드들을 전반적으로 수정,삭제했고,

강의 초반부분을 보고 따라해보며 회원가입, 비밀번호 암호화, 로그인, 토큰생성 까지 완료를 했다.

 

이번 강의를 보고 배운 JWT 토큰 생성 방식의 인증/인가 중

JWT의 설정을 하는 코드를 올려본다.

package com.example.mytodoapp.infra.swagger.security.jwt

import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jws
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.nio.charset.StandardCharsets
import java.time.Duration
import java.time.Instant
import java.util.*

@Component
class JwtPlugin(
    @Value("\${auth.jwt.issuer}") private val issuer: String,
    @Value("\${auth.jwt.secret}") private val secret: String,
    @Value("\${auth.jwt.accessTokenExpirationHour}") private val accessTokenExpirationHour: Long,
) {

    // kotlin에서는 try catch 대신에 아래와 같은 Result 형태로 exception 처리를 할 수 있습니다.
    fun validateToken(jwt: String): Result<Jws<Claims>> {
        return kotlin.runCatching {
            val key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
            // 우리의 key로 서명을 검증하고, 만료시간을 체크합니다.
            Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt)
        }
    }

    fun generateAccessToken(subject: String, email: String, role: String): String {
        // subject, 만료기간과 role을 설정합니다.
        return generateToken(subject, email, role, Duration.ofHours(accessTokenExpirationHour))
    }


    private fun generateToken(subject: String, email: String, role: String, expirationPeriod: Duration): String {
        // custom claim을 설정합니다.
        val claims: Claims = Jwts.claims()
            .add(mapOf("role" to role, "email" to email))
            .build()

        val key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
        val now = Instant.now()

        return Jwts.builder()
            .subject(subject)
            .issuer(issuer)
            .issuedAt(Date.from(now))
            .expiration(Date.from(now.plus(expirationPeriod)))
            .claims(claims)
            .signWith(key)
            .compact()
    }

}

아직은 완전 이해했다기 보단 일단 따라쳐본 느낌이다.

토큰안에 Id, 이메일, 이름, 역할 등등이 들어가고 이를 암호화 하는데

나는 이중에서 Id값을 빼와서 게시글에 유저이름을 남기거나, 본인이 만든 게시글과 댓글만 수정과 삭제가 가능하게 하는등의 코드를 짤 예정이다.

 

아직은 어떻게 하는지 모르기에 일단은 조금더 공부해봐야겠다.

 

오늘의 한마디 : 사실 기존 TodoApp을 처음부터 만들면 모를까 있던 코드를 수정, 삭제하는게 상당히 오래걸리고 오류도 많이 나서 정말 진이 빠지도록 몰두하다보니 엄청 힘이들었다. 다음번에는 좀더 잘 가늠해봐서 코드를 새로짤지 수정하는 쪽으로 할지 선택해야겠다.