Spring Framework에서 API에 대한 보안을 적용하고자 한다. 보통, 스웨거 및 로그인 같은 보안이 필요하지 않은 API를 제외한 다른 API에 대해 보안을 적용한다.
여러가지 방법 중, Interceptor에서 보안(인증)을 적용하는 방법이 있다.
왜 인터셉터에서 인증을 적용할까?

Filter에서는 URI(목적지), Header(어떤 인증을 할 것인지) 등을 알 수 있지만, 해당 요청이 어떤 컨트롤러로 가는지는 Filter에서 알 수 없다.
→ 따라서, Filter에서 인증을 하는 것은 의미가 없다.
Interceptor에서는 위 정보를 모두 알 수 있고, 컨트롤러의 권한을 모두 알 수 있다.
→ 따라서, 보통 Interceptor에서 해당 요청을 인증하는 부분을 담당한다.
package org.delivery.api.interceptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Slf4j
@RequiredArgsConstructor
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
}
→ 인터셉터를 상속받은 클래스를 생성한다.
package org.delivery.api.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Slf4j
@RequiredArgsConstructor
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("Authorization Interceptor url : {}", request.getRequestURI());
// WEB, Chrome의 경우 GET, POST OPTIONS = pass
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
return true;
}
// js, html, png 등 resource를 요청하는 경우 -> pass
if (handler instanceof ResourceHttpRequestHandler) {
return true;
}
// TODO: header 검증
return true;
}
}
→ preHandle 메소드를 구현하고, 로그을 찍어준다.
→ 그리고 웹(특히 크롬)의 경우 GET이나 POST와 같은 API를 요청하기 전에 OPTION이라는 API를 요청해서 해당 API를 지원하는지 체크하는 API를 먼저 보낸다. 이 OPTION API는 그냥 통과하도록 설정해준다.
→ js, html, png 등 리소스를 요청하는 경우도 마찬가지로 그냥 통과시켜준다.
→ 인증 검사는 추후에 하도록 일단 비워둔다.
이제 인터셉터를 생성했으니, Configuration을 통해 등록하면 된다.
WebConfig라는 클래스를 생성하고, 아래와 같이 작성한다.
package org.delivery.api.config.web;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.delivery.api.interceptor.AuthorizationInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final AuthorizationInterceptor authorizationInterceptor; // 인터셉터 자동 주입
private List<String> OPEN_API = List.of( // 기본 주소 이외에 공개할 주소
"/open-api/**"
);
private List<String> DEFAULT_EXCLUDE = List.of( // 기본 주소 (공개)
"/",
"favicon.ico", // 아이콘
"/error"
);
private List<String> SWAGGER = List.of( // 스웨거 주소
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**"
);
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor)
.excludePathPatterns(OPEN_API)
.excludePathPatterns(DEFAULT_EXCLUDE)
.excludePathPatterns(SWAGGER)
;
}
}
→ @RequiredArgsConstructor를 통해 인터셉터를 자동 주입 시켜준다.
→ 중간에 리스트들은 인터셉터가 그냥 통과시켜줄 수 있도록 excludePathPatterns()에 넣어주는 용도이다.
Share article