: permitAll()과 JWT Filter WhiteList의 차이점 및 통합 관리 방안
permitAll()은 Spring Security의 인가 단계에서 작동
클라이언트가 보낸 요청이 모든 Spring Security 필터 체인을 거쳐서 마지막 단계인 AuthorizationFilter에서 권한 검사를 수행할 때 "이 경로는 인증 없이 허용한다"고 판단하는 메커니즘
중요한 점은 permitAll()로 설정된 경로라도 모든 필터를 거친다는 것
즉, JWT 필터, CSRF 필터 등 모든 보안 필터를 통과한 후 마지막에 인가 단계에서만 허용된다!
JWT Filter의 WhiteList(shouldNotFilter 메서드)는 인증 단계에서 작동한다
➡️ 필터 체인의 초기 단계에서 특정 경로에 대해 JWT 검증 자체를 건너뛰는 방식
필터 실행 순서 때문이다.
Spring Security의 필터 실행 순서
permitAll()만 설정하면, JWT 필터가 먼저 실행되어 토큰이 없는 요청에 대해 인증 실패를 발생시킬 수 있음
➡️ 이후 인가 단계에서 permitAll()이 적용되지만, 이미 인증 단계에서 문제가 발생한 상태이기때문에,,
Spring Security 환경에서 구현할때, permitAll()과 JWT Filter의 WhiteList를 하나의 체계로 통합 관리하는 것은 코드 일관성과 유지보수성을 크게 향상시킨다!
인증 단계에서 작동
→ 필터 체인의 초기 단계에서 특정 경로에 대해 JWT 검증 자체를 건너뛰는 방식
➡️ true를 반환하면 해당 요청에 대해 필터 처리를 완전히 우회할 수 있다!
나는 하나의 클래스에서 허용되는 경로를 모두 명시하여, Filter와 SecurityConfig에서 모두 재사용할 수 있는 방식을 선택했다.
@Component
public class SecurityPaths {
public static final String[] PUBLIC_PATHS = {
"/api/auth/**",
"/경로들", ...
};
}
컴포넌트로 해당 경로들을 등록해놓고,
// JwtFilter
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String requestURI = request.getRequestURI();
return Arrays.stream(SecurityPath.PUBLIC_PATH)
.anyMatch(path -> {
if (path.endsWith("/**")) {
return requestURI.startsWith(path.substring(0, path.length() - 3));
}
return requestURI.startsWith(path);
});
}
OncePerRequestFilter를 상속한 JWTFilter 내부에 shouldNotFilter를 Override해서 SecurityPath에 명시한 경로들의 인증,인가를 무시할 수 있도록 설정해주자
또한 SecurityConfig의 authorizeHttpRequests에도 공통 경로를 추가하면 된다.
//인증 URL 범위 설정
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers(
SecurityPath.PUBLIC_PATH).permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN") //어드민 권한 필요 (문제 생성, 관리 등)
.anyRequest().authenticated() //나머지는 일반 인증
)
모든 public 경로를 하나의 클래스에서 관리하여 중복을 제거하고 일관성을 보장할 수 있음!