개발일지/문제 해결

io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted. 에러 해결

티에리앙리 2022. 8. 30. 18:46

마이크로서비스(user-service)와 apigateway 서비스를 사용하던중에

RestTemplate 을 적용하고 api 요청을 테스트하는데

user-service를 apigateway 서비스에 등록한데로 get방식이 요청안됐다.

 

apigateway-service의 application.yml에

get방식은 AuthorizationHeaderFilter를 거치도록 등록해놨다.

spring:
  application:
    name: apigateway-service
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
  cloud:
    gateway:
      default-filters:
        - name: GlobalFilter  # GlobalFilter 등록
          args:
            baseMessage: Spring Cloud Gateway Global Filter
            preLogger: true
            postLogger: true
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates: # 조건절이다.
            - Path=/user-service/login  # 로그인
            - Method=POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
          # /user-service/(?<segment>.*) 이런 형식의 데이터가 들어오면 /$\{segment} 형식으로 바꾸겠다.
        - id: user-service
          uri: lb://USER-SERVICE
          predicates: # 조건절이다.
            - Path=/user-service/users  # 회원가입
            - Method=POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
        - id: user-service
          uri: lb://USER-SERVICE #
          predicates: # 조건절이다.
            - Path=/user-service/**
            - Method=GET
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/user-service/(?<segment>.*), /$\{segment}
            - AuthorizationHeaderFilter
            # /user-service/** 로 들어오는 건 위에 따로 표시한 /login(로그인)과 /users(회원가입)를 제외하고 AuthorizationHeaderFilter 를 거친다.
            # 즉, 인증이 필요없는 로그인과 회원가입은 AuthorizationHeaderFilter를 적용시키지 않았고 나머지는 적용시켰다.

 

그런데 우선

POST 방식 요청인

127.0.0.1:8000/user-service/users

127.0.0.1:8000/user-service/login 은 문제 없이 잘됐다.

 

하지만 GET 방식 요청인

127.0.0.1:8000/user-service/users

127.0.0.1:8000/user-service/users/welcome

127.0.0.1:8000/user-service/users/health_check

127.0.0.1:8000/user-service/users/{userId} 은 

디버깅 브레이크 포인트도 안걸리고 그냥 401 에러가 발생했다.

 

즉,

127.0.0.1:8000/user-service/login 으로 얻은 response의 Header에 있는 token을가지고

요청할 때 Bearer Token에 넣어도 401 에러가 발생한다..

 

분명 apigateway-service의 application.yml에

get방식은 AuthorizationHeaderFilter 를 걸어줬는데 안돼서 난감했다..

 

그래서 디버깅을 다시 해보았다.

apigateway-service의

AuthorizationHeaderFilter 에  isJwtValid 의 .parseClaimsJws(jwt).getBody() 에서

Step Over로 디버깅을하는데

private boolean isJwtValid(String jwt) {
    boolean returnValue = true;

    String subject = null;

    try{
        subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
                .parseClaimsJws(jwt).getBody()
                .getSubject();  // 토큰의 Body에서 Subject를 가져온다.
    } catch (Exception ex){
        returnValue = false;
    }

    if(subject == null || subject.isEmpty()) {
        returnValue = false;
    }

    return returnValue;
}

io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

에러가 발생했다.

 

 

검색해본결과

각 마이크로 서비스의 secret_token 값을 같게 해줘야 되는데 다르게 설정되어 있어서 문제가 발생했다.

 

현재 apigateway-service는 ecommerce.yml 을 가져오게 설정이 돼있었고

spring:
  cloud:
    config:
      uri: http://127.0.0.1:8888
      name: ecommerce # ecommerce.yml 파일을 가져온다.

user-service는 user-service.yml을 가져오도록 설정이 돼있었다.

spring:
  cloud:
    config:
      uri: http://127.0.0.1:8888
      name: user-service # user-service.yml 파일을 가져온다.

하지만 user-service.yml파일과 ecommerce.yml 파일의 token.secret 값이 달랐다.

 

user-service.yml에는 다음과 같이 등록돼있었고

token:
  expiration_time: 86400000
  secret: user_token_native_user_service

ecommerce.yml에는 다음과같이 등록돼있었다.

token:
  expiration_time: 86400000
  secret: user_token_native_ecommerce

 

 

즉, token.secret이 달랐다.. 

이 값을 동일하게 하니까 user-service 포트가아니라

apigateway-service를 활용해서 요청을해도 get방식으 요청이 잘됐다.