[Spring Security] - SecurityContextPersistenceFilter 와 SecurityContextHolderFilter

목차

기존에 인증을 하고 SecurityContext 를 생성하면 로그인 Session 이 유지가 됐는데, 새 프로젝트를 개발하면서 Reqeust 가 끝나면 인증이 풀리는 것을 알게 됐습니다. Spring Security 5.7 버전 이상부터는 SecurityContextPersistenceFilter 가 Deprecated 되고 SecurityContextHolderFilter 로 대체돼면서 이런 문제가 생긴거 같아 내용을 정리했습니다.

🔎 SecurityContextPersistenceFilter

SecurityContextPersistenceFilter 에서는 인증을 위해 SecurityContextRepository 에 저장된 SecurityContext 정보를 가져와 인증 처리를 하고 요청이 종료되면 SecurityContext 정보를 SecurityContextRepository 에 저장합니다.

SecurityContextPersistenceFilter 동작 과정

SecurityContextPersistenceFilter 에서는 saveContext 를 이용해 SecurityContext 를 저장합니다.

SecurityContextPersistenceFilter.java
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
...

// SecurityContext 를 가져옵니다.
SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);
try {
this.securityContextHolderStrategy.setContext(contextBeforeChainExecution);
if (contextBeforeChainExecution.getAuthentication() == null) {
logger.debug("Set SecurityContextHolder to empty SecurityContext");
}
else {
if (this.logger.isDebugEnabled()) {
this.logger
.debug(LogMessage.format("Set SecurityContextHolder to %s", contextBeforeChainExecution));
}
}
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
SecurityContext contextAfterChainExecution = this.securityContextHolderStrategy.getContext();
this.securityContextHolderStrategy.clearContext();

// SecurityContext 를 저장합니다.
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
}

🔎 SecurityContextHolderFilter

SecurityContextHolderFilter 에서는 인증을 위해 SecurityContextRepository 에 저장된 SecurityContext 정보를 가져와 인증 처리를 진행합니다. 하지만 SecurityContextPersistenceFilter 와는 다르게 SecurityContextRepository 에 저장하지는 않습니다.

SecurityContext 의 변경 사항을 자동으로 저장하지 않으므로, 개발자가 필요에 따라 명시적으로 저장해야 합니다.

SecurityContextHolderFilter 동작 과정

SecurityContextHolderFilter 에서는 SecurityContextPersistenceFilter 와 달리 SecurityContext 를 저장하는 로직이 없습니다.

SecurityContextHolderFilter.java
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
...

// SecurityContext 를 가져옵니다.
Supplier<SecurityContext> deferredContext = this.securityContextRepository.loadDeferredContext(request);
try {
this.securityContextHolderStrategy.setDeferredContext(deferredContext);
chain.doFilter(request, response);
}
finally {
this.securityContextHolderStrategy.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
Share