Spring Boot 환경에서 JWT 인터셉터 구축 및 Knife4j 문서 접근 이슈 해결

프로젝트에 JWT 기능을 추가하기 위해 pom.xml에 다음 의존성을 추가합니다.

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.4.0</version>
</dependency>

JWT 유틸리티 클래스

토큰의 생성과 검증을 담당하는 유틸리티 클래스를 작성합니다.

TokenManager
package com.example.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;

public class TokenManager {

    private static final String SECRET = "mySecretKey2024";
    private static final long EXPIRATION_MS = 1000 * 60 * 60 * 12;

    public static String createToken(Map<String, Object> payload) {
        return JWT.create()
                .withClaim("data", payload)
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_MS))
                .sign(Algorithm.HMAC256(SECRET));
    }

    public static Map<String, Object> verifyToken(String token) {
        return JWT.require(Algorithm.HMAC256(SECRET))
                .build()
                .verify(token)
                .getClaim("data")
                .asMap();
    }
}

단위 테스트

테스트 의존성을 추가합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

토큰 생성 테스트

@Test
void generateToken() {
    Map<String, Object> userInfo = new HashMap<>();
    userInfo.put("userId", 1001);
    userInfo.put("nickname", "devUser");

    String jwt = JWT.create()
            .withClaim("user", userInfo)
            .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))
            .sign(Algorithm.HMAC256("mySecretKey2024"));

    System.out.println(jwt);
}

토큰 검증 및 파싱 테스트

@Test
void validateToken() {
    String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVzZXJJZCI6MTAwMSwibmlja25hbWUiOiJkZXZVc2VyIn0sImV4cCI6MTcyMTAxMjY5Nn0.xxx";

    DecodedJWT decoded = JWT.require(Algorithm.HMAC256("mySecretKey2024"))
            .build()
            .verify(jwt);

    Map<String, Claim> claims = decoded.getClaims();
    System.out.println(claims.get("user"));
}

인증 인터셉터 구현

요청 헤더의 토큰을 검사하는 인터셉터를 만듭니다.

AuthInterceptor
package com.example.interceptor;

import com.example.security.TokenManager;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        String bearer = req.getHeader("Authorization");

        try {
            Map<String, Object> userData = TokenManager.verifyToken(bearer);
            req.setAttribute("userData", userData);
            return true;
        } catch (Exception ex) {
            res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        // 리소스 정리 로직
    }
}

인터터 등록 및 예외 경로 설정

WebMvcConfigurer를 구현하여 인터셉터를 등록하고, 특정 경로는 검증에서 제외합니다.

InterceptorConfig
package com.example.config;

import com.example.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/api/auth/login",
                        "/api/auth/signup",
                        "/doc.html/**",
                        "/swagger-resources/**",
                        "/webjars/**",
                        "/v3/**"
                );
    }
}

Knife4j 접근 불가 문제 해결

인터셉터 등록 후 Knife4j 문서 페이지가 접근 불가한 경우, excludePathPatterns에 Swagger 관련 경로를 추가해야 합니다.

경로 패턴설명
/doc.html/**Knife4j 메인 UI 페이지
/swagger-resources/**Swagger 리소스 정보
/webjars/**정적 웹 자원
/v3/**OpenAPI 3.0 스펙 엔드포인트

Spring Boot 3.x 환경에서 Knife4j를 사용할 때는 위 4개 패턴을 모두 제외 목록에 포함시켜야 정상적으로 문서 페이지에 접근할 수 있습니다.

태그: jwt Spring Boot Knife4j Interceptor swagger

6월 21일 20:46에 게시됨