MSA 공부 (User Microservice - JWT 처리 과정) - 12

진병욱·2023년 11월 6일

Spring Cloud MSA 공부

목록 보기
12/20
post-thumbnail

먼저 글 작성에 앞서 해당 시리즈는 Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의를 참고하여 필요한 내용들을 정리한 것임을 밝힙니다.

API Gateway dependency 추가

  • 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

Mono, Flux

  • Spring 5.0에서 등장한 개념
  • 클라이언트 요청이 들어왔을 때 반환해주는 타입
  • Mono : 단일, Flux : 다중
  • 비동기 데이터 처리 방식

JDK 11 버전을 사용할 경우, jwt 라이브러리를 추가하는 것만으로는 토큰을 사용할 때 필요한 라이브러리가 모두 import되지 않기 때문에, javax.xml.bind를 종속성에 추가해주어야 한다.

profile
새로운 기술을 접하는 것에 망설임이 없고, 부족한 것이 있다면 항상 배우고자 하는 열정을 가지고 있습니다!

0개의 댓글