Dev Stories/백엔드(Back-End)

[Spring Security] OncePerRequestFilter를 활용한 인증 제외 URL 설정

레드트레인 2025. 6. 9. 23:00
반응형

OnceRequestFilter는 Spring Security에서 필터 체인의 각 요청마다 한번씩 실행을 하게 된다. Spring Security 설정에 인증 정보를 확인하기 위해 OnceRequestFilter를 상속받아 구현한다. Filter 클래스를 상속받아 구현하게 된다.

OnceRequestFilter shouldNotFilter, doFilterInternal 두개의 추상 메서드가 있다.

package org.springframework.web.filter;

public abstract class OncePerRequestFilter extends GenericFilterBean {

	...

	/**
	 * Can be overridden in subclasses for custom filtering control,
	 * returning {@code true} to avoid filtering of the given request.
	 * <p>The default implementation always returns {@code false}.
	 * @param request current HTTP request
	 * @return whether the given request should <i>not</i> be filtered
	 * @throws ServletException in case of errors
	 */
	protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
		return false;
	}
    
    ...
    
   	/**
	 * Same contract as for {@code doFilter}, but guaranteed to be
	 * just invoked once per request within a single request thread.
	 * See {@link #shouldNotFilterAsyncDispatch()} for details.
	 * <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
	 * default ServletRequest and ServletResponse ones.
	 */
	protected abstract void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException;

	...
}

특정 엔드포인트는 필터를 제외

다음은 특정 엔드포인트는 필터를 제외하는 설정이다. 메서드명이 shouldNotFilter인 것을 보면 어떤 결과가 나오는지 예측해 볼 수 있는데, 매칭 될 때 true로 리턴이 되기 때문에 필터를 타지 않습니다.

    // 필터를 적용할 엔드포인트 목록
    private final List<String> securedUrls = List.of(
        "/api/signin",
        "/api/signup"
    );

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String path = request.getRequestURI();
        return securedUrls.stream().anyMatch(path::startsWith); 
    }

특정 엔드포인트만 필터 적용

특정 엔드포인트만 필터를 적용하고 목록에 없는 나머지 요청은 필터를 건너뛰는 설정이다.

    // 필터를 적용할 엔드포인트 목록
    private final List<String> excludeUrls = List.of(
        "/api/user/profile",
        "/api/user/settings"
    );

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String path = request.getRequestURI();
        return excludeUrls.stream().noneMatch(path::startsWith); 
    }

와일드카드를 적용하여 패턴 매칭

앞서 설명한 anyMatch, nonMatch의 startsWith()만 사용해서는 엔드포인트 목록의 /api/user/** 과 같은 패턴은 적용할 수 없다. 와일드 카드(*)나 정규 표현식을 사용하려면 직접 매칭 로직을 구현해야 한다.

Spring에서 제공하는 AntPathMatcher를 사용하여 패턴에 맞는 URL을 매칭할 수 있다. pathMather.match(patern, path)로 와일드카드(**)를 활용한 여러 경로를 한 번에 필터링 한다.

    // AntPathMatcher 
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    // 필터를 적용할 엔드포인트 목록 (와일드카드 지원)
    private final List<String> securedPatterns = List.of(
    	"/api/user/**"
    );

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String path = request.getRequestURI();
        return securedPatterns.stream().noneMatch(pattern -> pathMatcher.match(pattern, path));
    }
반응형