• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

jwt 인증401 뜹니다.

24.04.09 17:40 작성 조회수 98

0

@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
    Environment env;

    public AuthorizationHeaderFilter(Environment env) {
        super(Config.class);
        this.env = env;
    }

    public static class Config {
        //
    }


    @Override
    public GatewayFilter apply(Config config) {
        // ServerWebExchange 파라미터는 필터가 동작하는 동안 현재 요청 및 응답에 대한 정보를 제공한다.
        // 비동기 서버 Netty 에서는 동기 서버(ex:tomcat)와 다르게 request/response 객체를 선언할 때 Server~ 를 사용한다.
        GatewayFilter filter = (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            // 요청 헤더에 "Authorization" 헤더가 포함되어 있는지 확인한다.
            if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                // "Authorization" 헤더가 없는 경우, UNAUTHORIZED(401) 상태로 에러 응답을 반환.
                return onError(exchange, "No Authorization header", HttpStatus.UNAUTHORIZED);
            }

            // "Authorization" 헤더에서 JWT 토큰을 추출.
            String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
            // "Bearer " 문자열을 삭제하고 토큰만 추출
            String jwt = authorizationHeader.replace("Bearer ", "");

            log.info("authorizationHeader : " + authorizationHeader);
            log.info("jwt : " + jwt );
            // 추출한 JWT 토큰의 유효성을 확인.
            if (!isJwtValid(jwt)) {
                return onError(exchange, "JWT Token is not valid", HttpStatus.UNAUTHORIZED);
            }

            // JWT 토큰이 유효한 경우, 다음 필터로 요청을 전달.
            return chain.filter(exchange);
        };

        return filter;
    }



    private boolean isJwtValid(String jwt) {
        // 반환값으로 사용할 boolean 변수를 초기값 true로 설정
        boolean returnValue = true;

        // JWT의 'subject'를 저장할 변수 초기화
        String subject = null;

        try {
            // 환경 변수에서 토큰의 비밀 키 가져오기
            String secretKey = env.getProperty("token.secret");
            log.info("secretkey : " + secretKey);
            // JWT 파서를 생성하고 토큰의 비밀 키 설정
            JwtParser jwtParser = (JwtParser) Jwts.parser().setSigningKey(secretKey);

            // JWT 파서를 사용하여 토큰을 파싱하고 Claims 객체를 반환
            Claims claims = jwtParser.parseClaimsJws(jwt).getBody();

            // 토큰에서 'subject' 정보 추출
            subject = claims.getSubject();
            log.info("subject:" + subject);
        } catch (Exception e) {
            // 예외가 발생하면 JWT가 유효하지 않다고 판단하고 반환값을 false로 변경
            returnValue = false;
        }

        // 'subject' 값이 비어있으면 JWT가 유효하지 않다고 판단하고 반환값을 false로 변경
        if (subject == null || subject.isEmpty()) {
            returnValue = false;
        }

        // 최종적으로 JWT의 유효성 여부를 나타내는 반환값을 반환
        return returnValue;
    }

    // Mono, Flux -> Spring WebFlux (기존의 SpringMVC 방식이 아니기때문에 Servlet 을 사용하지 않음)
    private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);

        log.error(err);
        return response.setComplete();
    }
}

authorizationHeader : Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6Iltjb20uZXhhbXBsZS5qd3Rqd3QuZmlsdGVyLkN1c3RvbVVzZXJEZXRhaWxzJDFANjIxMDI1MGNdIiwiaWF0IjoxNzEyNjUxODYzLCJleHAiOjE3MTI2NTE4OTl9.oH-cw5zNVM43LIEj173W0zof5PcbhIa6CiTq1lEHRWs

 

jwt : eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6Iltjb20uZXhhbXBsZS5qd3Rqd3QuZmlsdGVyLkN1c3RvbVVzZXJEZXRhaWxzJDFANjIxMDI1MGNdIiwiaWF0IjoxNzEyNjUxODYzLCJleHAiOjE3MTI2NTE4OTl9.oH-cw5zNVM43LIEj173W0zof5PcbhIa6CiTq1lEHRWs

 

secretkey : user_token

 

JWT Token is not valid

이렇게 뜨는데 뭐가 문제일까요??

답변 2

·

답변을 작성해보세요.

0

안녕하세요, 이도원입니다.

말씀하신 내용처럼 authorizationHeader 의 Bearer 토큰과 jwt가 동일한게 맞다면, user-service에서 토큰을 생성할 때 사용한 secret_key가 apigateway-service에서 토큰의 유효성 검사를 위해 사용하는 secret_key가 같은지와 유효시간에 문제가 없는지 등을 확인해 보셔야 합니다. 우선 apigateway-service의 AuthorizationHeaderFilter 클래스의 isJwtValid 메소드에서 디버깅을 해 보시면서, 한 단계식 확인해 보시면 좋을 것 같습니다.

image

추가 질문이 있으시면 글 남겨 주세요.

감사합니다.

 

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.04.09

안녕하세요, 인프런 AI 인턴입니다.

문제를 해결하려면 JWT 토큰이 올바르게 생성되었는지, 그리고 해당 토큰을 검증할 때 사용한 시크릿 키(secretKey)가 JWT 토큰 생성 시 사용한 것과 정확히 일치하는지 확인해야 합니다. “JWT Token is not valid”라는 메시지는 대체로 JWT 토큰의 형식이 잘못되었거나, 시크릿 키가 일치하지 않을 때 발생합니다.

즉, 여러가지 문제가 있을 수 있지만, 주요 확인 포인트는 다음과 같습니다:
1. JWT 토큰 생성: 토큰 생성 시 사용한 암호화 알고리즘과 시크릿 키가 올바른지 확인합니다.
2. 시크릿 키 일치성: 토큰 검증 시 사용한 시크릿 키가 생성 시 사용한 것과 완전히 동일한지 확인합니다.
3. 토큰 유효기간 확인: exp (Expiration Time) 필드를 확인하여 토큰이 유효한 기간 내에 있는지 검증합니다. 만료된 토큰을 사용하면 유효하지 않다는 결과가 발생합니다.

다음의 질문 링크에 비슷한 상황에 대한 답변이 있습니다. 이 경우에는 HTTP Method 문제로 인해 발생했으나, 이와 유사한 설정 문제로 유효하지 않은 JWT 오류가 발생할 수 있습니다. 설정이 올바르게 적용되었는지 다시 한번 확인하시기 바랍니다.

추가로, JWT의 isJwtValid 메서드 내에서 발생할 수 있는 다양한 예외에 대해서도 자세한 로깅을 수행하여 보다 정확한 원인 분석을 시도해 보시는 것을 추천드립니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.