Spring Security Filter - 인증, 인가 (2)

KwonKusang·2023년 2월 15일
0

Spring Security

목록 보기
2/2
post-thumbnail
post-custom-banner

시큐리티는 앞서 살펴본 인증 객체와 함께 SecurityFilter의 흐름에 따라 인증, 인가를 처리한다. 필자가 느끼기엔 필터들마다 각각의 역할이 명확하게 느껴졌다. 때문에 10개가 넘는 필터들이 서로를 해치치않고 자신의 기능에 충실했다.

지금부터는 각 필터의 역할이 무엇인가에 집중해보면 좋을 것 같다.

WebAsyncManagerIntegrationFilter

비동기 처리인 @Async를 사용할 때 별도의 Thread에서 처리하게 된다. 하지만 SecurityContext는 Thread-Safe 하기 때문에 별도의 처리가 필요하다.

SecurityContextHolder
SecurityContext가 ThreadLocal에 저장되기 위한 객체이다.

자식 스레드에 공유하게 해주는 전략으로 변경한다.

  • Default MODE_THREADLOCAL -> MODE_INHERITABLETHREADLOCAL
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);

필터 안의 SecurityContextCallableProcessingInterceptor는 다음과 같은 작업을 한다.

  • preProcess() : Callable 실행 전, Async의 Thread로 넘어가기 직전에 SecurityContext를 SecurityContextCallableProcessingInterceptor에 저장한다.
  • postProcess() : Callable 실행 후, 저장되어 있던 SecurityContext를 제거한다.
	@Override
	public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
		this.securityContextHolderStrategy.setContext(this.securityContext);
	}

	@Override
	public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
		this.securityContextHolderStrategy.clearContext();
	}

SecurityContextHolderFilter

SecurityContextPersistenceFilter가 Spring 5.7.2부터 @Deprecated 되었지만, 역할은 거의 비슷하다.
시큐리티는 기본적으로 HttpSessionSecurityContextRepository을 사용하여 인증 정보가 HttpSession에 저장된다. 유저 요청이 오면 SecurityContext를 가져오고 SecurityContextHolder에 세팅한다.

인증 객체를 살펴봤을 때 SecurityContextHolder에 SecurityContext가 저장된다는 것을 알 수 있었다. 저장된 인증 객체를 SecurityContextRespository를 이용하여 정보를 가져온 것이다.

차이점이라면,

  • SecurityContextPersistenceFilter는 비인증 유저 요청이 오면 Session에 저장된 SecurityContext가 없으니 새로운 SecurityContext를 생성한다. 이후 응답 시점에 Session에 저장한다.
  • SecurityContextHolderFilter는 SecurityContext를 읽기만 하고 저장하는 과정에 없다.

HeaderWriterFilter

HeaderWriterFilter는 요청 전/후에 시큐리티 관련 헤더를 Response에 추가한다.

	// 요청 전
	private void doHeadersBefore(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		writeHeaders(request, response);
		filterChain.doFilter(request, response);
	}
	// 요청 후
	private void doHeadersAfter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request, response);
		HeaderWriterRequest headerWriterRequest = new HeaderWriterRequest(request, headerWriterResponse);
		try {
			filterChain.doFilter(headerWriterRequest, headerWriterResponse);
		}
		finally {
			headerWriterResponse.writeHeaders();
		}
	}

shouldWriteHeadersEagerly 설정에 따라서 response에 Header를 요청 전, 요청 후에 header를 추가할지를 판단한다. 기본값은 False로 요청 후에 추가한다.

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		if (this.shouldWriteHeadersEagerly) {	// Default false
			doHeadersBefore(request, response, filterChain);
		}
		else {
			doHeadersAfter(request, response, filterChain);
		}
	}
profile
안녕하세요! 백엔드 개발자 권구상입니다.
post-custom-banner

0개의 댓글