본문 바로가기
Spring

Spring Boot spring-security-oauth2-jose 사용해 JWKS URI로 JWT 검증하기

by wadekang 2024. 2. 8.

 

Dependency 추가

1. Maven

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-oauth2-jose -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
    <version>6.2.1</version>
</dependency>

 

2. Gradle

// https://mvnrepository.com/artifact/org.springframework.security/spring-security-oauth2-jose  
implementation group: 'org.springframework.security', name: 'spring-security-oauth2-jose', version: '6.2.1'

 

구현

Spring Cloud Gateway에서 요청을 받았을 때 JWT를 검증하는 필터를 구현

@Slf4j
@Component
public class AuthorizationHeaderFilter implements GatewayFilter {

    private final JwtDecoder jwtDecoder;

    private static final String JWKS_URI = "http://localhost:9080/jwks";

    public AuthorizationHeaderFilter() {

        jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWKS_URI).build();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();

        String token = request.getHeaders().getFirst("Authorization");

        if (token != null && token.startsWith("Bearer ")) {
            log.info("AuthFilter ===> requestId: {}, token: {}", request.getId(), token);

            // Remove "Bearer " from token
            token = token.substring(7);

            try {
                // JWT 유효하지 않을 경우 Exception 발생
                Jwt jwt = jwtDecoder.decode(token);

                log.info("AuthFilter ===> requestId: {}, jwt: {}", request.getId(), jwt.getClaims());

                return chain.filter(exchange);
            } catch (BadJwtException e) {
                // JWT 검증 실패 시 처리
                log.error(e.getMessage(), e);
                
                ...
            }
        }
        
        // 토큰이 없거나 형식에 맞지 않을 때 처리
        ...
    }
}

 

jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWKS_URI).build();

Jwt jwt = jwtDecoder.decode(token);

 

위와 같이 JwtDecoder에 JWKS_URI를 지정해 두면 jwtDecoder.decode(token) 구문에서 JWT를 검증하고 파싱 할 때 JWKS_URI를 호출하여 JWKS를 가져온 후 JWKS 내의 키 정보를 통해 JWT를 검증하도록 함

라이브러리 자체적으로 캐싱을 하여 매 요청마다 JWKS URI를 호출하지는 않고 캐싱 주기에 따라 호출하는 것으로 보임 (JWKS API가 구현되어 있는 Auth 모듈에서 로그를 확인해 보면 매 요청마다 JWKS API가 호출되지 않음)

댓글