
먼저 글 작성에 앞서 해당 시리즈는 Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의를 참고하여 필요한 내용들을 정리한 것임을 밝힙니다.
Spring Security
JWT Token
게이트웨이에서 사용자로부터 받은 토큰을 검증하여 처리
위와 같은 내용들을 필터를 통해 검증
필터가 필요한 URI를 판별해서, 필요 없는 login, join과 같은 요청은 해당 필터를 적용하지 않고, 그 외에 유저의 인증이 필요한 부분에 해당 필터를 적용시켜 검증을 한다.
AuthorizationHeaderFilter.java
@Slf4j
@Component
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
/**
* 설정 관련 클래스 캐스팅
*/
public AuthorizationHeaderFilter() {
super(Config.class);
}
/**
* 필터 적용 메소드
* @param config 설정 관련 클래스
* @return GatewayFilter
*/
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 헤더에 Authorization이 없을 경우
if (!request.getHeaders().containsKey("Authorization")) {
return onError(exchange, "No Authorization header", HttpStatus.UNAUTHORIZED);
}
// header 가져 오기
String authorizationHeader = request.getHeaders().get("Authorization").get(0);
// jwt 가져 오기
String jwt = authorizationHeader.replace("Bearer", "");
// jwt 유효성 검사
if (!isJwtValid(jwt)) {
return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED);
}
return chain.filter(exchange);
});
}
/**
* JWT 토큰이 유효한지 확인하는 메소드
* @param jwt 토큰
* @return boolean 토큰 유효 여부
*/
private boolean isJwtValid(String jwt) {
boolean result = true;
String subject = null;
// TODO: 추후 이 subject가 사용자가 넣었던 ID와 동일한 지 확인 하는 로직을 넣어도 좋을듯 함, redis에 refresh token을 저장하고 이를 통해 subject를 비교해봐도 좋을 듯 함
try {
subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
.parseClaimsJws(jwt).getBody().getSubject();
} catch (Exception e) {
result = false;
}
if (subject == null || subject.isEmpty()) {
result = false;
}
return result;
}
/**
* 에러 발생 시 처리하는 메소드
* @param exchange http 요청/응답 관련 메소드
* @param err 에러 메시지
* @param httpStatus 에러 상태 코드
* @return Mono<Void>
*/
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse(); // 응답
response.setStatusCode(httpStatus); // 상태 코드
log.error(err); // 에러 출력
return response.setComplete(); // 응답 세팅
}
/**
* Config 클래스
*/
public static class Config {
}
}
appplication.yml
routes:
- id : first-service
uri: lb://FIRST-SERVICE
predicates:
- Path=/first-service/login # 로그인 요청의 post에 한해서 필터를 적용
- Method=POST
filters:
- CustomFilter
- AuthorizationHeaderFilter
JDK 11 버전을 사용할 경우, jwt 라이브러리를 추가하는 것만으로는 토큰을 사용할 때 필요한 라이브러리가 모두 import되지 않기 때문에, javax.xml.bind를 종속성에 추가해주어야 한다.