io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted. 에러 해결
마이크로서비스(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방식으 요청이 잘됐다.