Spring/시큐리티 기본원리

시큐리티 기본 원리( 19 ) - RequestCacheAwareFilter

_Jin_ 2025. 1. 28.

RequestCacheAwareFilter 목적

해당 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 열두 번째의 필터이다.

 

RequestCacheAwareFilter는 이전 HTTP 요청에서 처리할 작업이 완료되지 못한 상태에서 현재 요청으로 함께 수행하기 위한 

기능을 수행한다.

 

비활성화 방법

커스텀 SecurityFilterChain에 기본적으로 등록되기에 아래와 같은 구문으로 비활성화 시킬 수 있다.

http
        .requestCache((cache) -> cache.disable());

 

RequestCacheAwareFilter 의 동작 예시

해당 필터의 목적을 봐선 왜 존재하는 지 와닿지 않을 수 있지만, 다음의 예시를 통해 수행하는 기능을 이해해보자.

 

1. 로그인하지 않은 사용자가 권한이 필요한 “/my” 경로에 접근
2. 권한 없음 예외가 발생하고 핸들러에서 “/my” 경로를 기억 후 핸들 작업 수행
3. 스프링 시큐리티가 “/login” 창을 띄움
4. username/password를 입력 후 인증을 진행
5. 로그인 이후 저장되어 있는 “/my” 경로를 불러내서 실행

 

대표적인 예시로 위처럼, 로그인 이전에 사용할 수 없는 권한에 접근하여 로그인 창을 통해 

로그인을 처리하고 이후에 본래 접근하려면 페이지로 접근하는 상황이 있다.

 

핸들 시점

그럼 어느 시점에 이전의 요청에 대한 정보를 기억하고 수행하는 것일까?

이와 같은 로직을 수행함에는 대표적으로 예외를 처리하는 필터인 ExceptionTranslationFilter에서 ExceptionTranslationFilter

이후에 발생하는 예외들을 모두 받도록 되어있다.

 

구체적으로  AccessDeniedException과 같은 몇 몇 예외 발생시 내부 메소드 sendStartAuthentication() 메소드가 실행되는데 여기서 requestCache를 저장한다.

protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
		AuthenticationException reason) throws ServletException, IOException {

	SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
	this.securityContextHolderStrategy.setContext(context);
	this.requestCache.saveRequest(request, response);
	this.authenticationEntryPoint.commence(request, response, reason);
}

 

 

주요 로직 

해당의 필터의 주요 로직은 아래와 같으며,

수행하는 바는 requestCache를 확인 후 현재 요청에 적용 시키는 것이다.

public class RequestCacheAwareFilter extends GenericFilterBean {

	private RequestCache requestCache;

	public RequestCacheAwareFilter() {
		this(new HttpSessionRequestCache());
	}

	public RequestCacheAwareFilter(RequestCache requestCache) {
		Assert.notNull(requestCache, "requestCache cannot be null");
		this.requestCache = requestCache;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
			
		// request 캐시에서 이전 요청에 캐싱해둔 데이터가 있는지 조회
		HttpServletRequest wrappedSavedRequest = this.requestCache.getMatchingRequest((HttpServletRequest) request,
				(HttpServletResponse) response);
				
		// 있다면 다음 필터로 넘길때 현재 요청에 덮어 쓰기
		chain.doFilter((wrappedSavedRequest != null) ? wrappedSavedRequest : request, response);
	}
}

댓글