본문 바로가기

카테고리 없음

게시글 작성중

2024-06-05T01:42:18.294+09:00 ERROR 10044 --- [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.NullPointerException: null
at org.example.domain.infra.jwt.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.kt:40) ~[main/:na]

 

로그인을 한뒤에 게시글을 작성하려고 하면 이것이 뜨게 된다.

 

그이유는 

package org.example.domain.infra.jwt

import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jws
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import jakarta.servlet.http.Cookie // javax가 아닌 jakarta를 사용
import jakarta.servlet.http.HttpServletResponse
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.Date

@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,
) {
    fun validateToken(jwt: String): Result<Jws<Claims>> {
        return kotlin.runCatching {
            val key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
            Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt)
        }
    }

    fun generateAccessTokenForSocialUser(
        subject: String,
        nickname: String,
        httpServletResponse: HttpServletResponse,
    ): String {
        val token = generateToken(subject, nickname, Duration.ofHours(accessTokenExpirationHour))
        addTokenToCookie(token, httpServletResponse)
        return token
    }

    fun generateAccessToken(
        subject: String,
        nickname: String,
    ): String {
        return generateToken(subject, nickname,  Duration.ofHours(accessTokenExpirationHour))
    }

    private fun generateToken(
        subject: String,
        nickname: String,
        expirationPeriod: Duration,
    ): String {
        val claims: Claims =
            Jwts.claims()
                .add(mapOf( "nickname" to nickname))
                .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()
    }

    private fun addTokenToCookie(
        token: String,
        httpServletResponse: HttpServletResponse,
    ) {
        val cookie = Cookie("jwt_token", token)
        cookie.isHttpOnly = false // JavaScript 에서 쿠키에 접근하지 못하도록 설정
        cookie.maxAge = (accessTokenExpirationHour * 60 * 60 * 24 * 7).toInt() // 약 8.4일
        cookie.path = "/" // 쿠키 객체를 모든 경로에서 쓸 수 있게 설정함.
        httpServletResponse.addCookie(cookie) // 쿠키 객체를 리스폰스에 담아서 클라이언트에게 주기.
    }
}

 

이걸 보면 40번째 줄에  val userPrincipal = UserPrincipal(id = userId, email = email)이 있는데, 내가 소셜로그인을 위해 이메일 부분을 제거했는데 이메일을 받게 되어 있어서 그런것이다.

 

if (jwt != null) {
            jwtPlugin.validateToken(jwt)
                .onSuccess {
                    val userId = it.payload.subject.toLong()
//                    val email = it.payload.get("email", String::class.java)
                    val nickname = it.payload.get("nickname", String::class.java) // 이메일 대신 닉네임 사용


                    val userPrincipal = UserPrincipal(id = userId, nickname = nickname)// 마찬가지 닉네임

                    val details = WebAuthenticationDetailsSource().buildDetails(request)
                    val auth = JwtAuthenticationToken(userPrincipal, details)

                    SecurityContextHolder.getContext().authentication = auth
                }
        }

       

 

이렇게 이메일을 닉네임으로 바꾸고

 

data class UserPrincipal(
    val id: Long,
    val nickname: String,
    )

 

이렇게 이메일을 없애고 닉네임만으로 한정한다.

 

그리고 게시글을 유저프린시팔로 로그인 한사람만 작성가능, 쓴 사람만 슈정, 삭제기능을 만드는 중이다.