Spring 프로젝트 시작하기 - 보안 ) Jwt Token 쿠키 예외처리

쿠키 검증로직까지 만들었다면 한가지 난감한 상황이 생긴다.

 

로그인을 할때도 토큰검증을 해버린다는것..

Interceptor는 별다른 처리가 없을때는 전체 API를 대상으로 동작하기 때문에 이런경우는 제외시켜주어야 한다.

 

이를 Custom Annotation으로 해결해보겠다.

 

ExcludeAuth

/* 인증예외 어노테이션 생성 (AuthIntercepter에서 예외처리) */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeAuth {
}

ExcludeAuth라는 이름의 annotation을 만들어줬다.

 

TokenAuthInterceptor

@Slf4j
@Component
public class TokenAuthInterceptor implements HandlerInterceptor {
    public static final String USER_ID = "X-USER-ID";
    private final JwtProvider jwtProvider;

    public TokenAuthInterceptor(JwtProvider jwtProvider) {
        this.jwtProvider = jwtProvider;
    }

    /**
     * 컨트롤러에 도착하기 직전 정보를 반환한다.
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //어노테이션 체크 - Controller에 @ExcludeAuth 어노테이션이 있는지 확인
        boolean hasAnnotation = hasAnnotation(handler, ExcludeAuth.class);
        try {
            if (!hasAnnotation) {
                JwtTokenDto tokenUser = jwtProvider.checkAccessToken(request);
                request.setAttribute("cIdx", tokenUser.getCIdx());
                request.setAttribute("uIdx", tokenUser.getUIdx());
                request.setAttribute("uId", tokenUser.getUId());
                MDC.put(USER_ID, tokenUser.getUId()); // 로그 출력시에 USER_ID값을 사용할 수 있도록 저장한다.
            } else {
                log.debug("Access Token 인증 제외");
            }
        } catch (Exception e) {
            throw new BadRequestException(ServerResponse.EXPIRE_TOKEN);
        }
        return true;
    }

    public <A extends Annotation> boolean hasAnnotation(Object handler, Class<A> annotationClass) {
        if (handler instanceof HandlerMethod handlerMethod) {

            // 메서드에 어노테이션이 있는지 확인
            return handlerMethod.getMethodAnnotation(annotationClass) != null;
        }
        return false; // 어노테이션이 없을 경우
    }
}

TokenAuthInterceptor에서도 로직을 추가해준다.

hasAnnotation는 handler에 특정한 annotationClass가 존재하는지 판별하는 함수이다.

 

ExcludeAuth.class가 없을때는 기본으로 token을 검사하게 된다.

token을 검사하지 않을때는 로그에 생략되었다고 남겼다.

 

적용

    @ExcludeAuth // !! 추가된 부분 !!
    @PostMapping("/login")
    public ResponseEntity<ServerResponse> login(HttpServletRequest request, @RequestBody AuthLoginRequest param, HttpServletResponse response) {
        log.debug("Controller [{}] 진입", Thread.currentThread().getStackTrace()[1].getMethodName());
        JwtTokenDto user = authService.login(request, param);

        // 로그인 토큰 생성
        jwtProvider.createAccessTokenString(user, response);

        return ResponseEntity.ok(ServerResponse.SUCCESS);
    }

Controller에서 Token 검증을 제외하고싶은 함수부분에 @ExcludeAuth을 추가하면 Token검사에서 제외된다.

 

테스트

토큰 없이도 정상로그인이 되는것이 확인된다.