개발자의 오르막
[SpringSecurity #05] Authentication 와 SecurityContextHolder 본문
[SpringSecurity #05] Authentication 와 SecurityContextHolder
계단 2020. 9. 27. 14:04# AuthenticationManager 가 인증을 마친 뒤 리턴 받은 Authentication 객체의 행방은?
→ SecurityContextHolder 안에 들어간 것
→ 로그인 할 때 로그인 정보가 밑의 2개의 필터에 의해 관리됨
# SecurityContextPersistenceFilter
- SecurityContext를 HTTP session에 캐시(기본 전략)하여 여러 요청에서 Authentication을 공유하는 필터
- SecurityContextRepository를 교체하여 세션을 HTTP session 이 아닌 다른 곳에 저장하는 것도 가능하다.
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
response);
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
SecurityContext contextAfterChainExecution = SecurityContextHolder
.getContext();
// Crucial removal of SecurityContextHolder contents - do this before anything
// else.
SecurityContextHolder.clearContext();
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
if (debug) {
logger.debug("SecurityContextHolder now cleared, as request processing completed");
}
}
만들어진 Context를 읽어와서 SecurityContextHolder 에 Set 해주는 구간이다.
넣어준 이후 작업이 완료된 이후에는 (Request, Response) 다시 ContextHolder 를 비워주는 작업을 해준다.
# UsernamePasswordAuthenticationFilter
- 폼 인증을 처리하는 시큐리티 필터
- 인증된 Authentication 객체를 SecurityContextHolder에 넣어주는 필터
- SecurityContextHolder.getContext().getAuthentication(authentication)
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
Authentication 인증정보가 있을 때에는 UsernamePasswordAuthenticationFilter 에 걸리게 된다.
return 부분에서 보면 AuthenticationManager 가 인증을 실행하고 있는 부분을 볼 수 있다.
# AbstractAuthenticationProcessingFilter
- UsernamePasswordAuthenticationFilter 의 부모
- attemptAuthentication 가 실행되어 authResult (Authentication 타입)으로 리턴됨
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
rememberMeServices.loginSuccess(request, response, authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
인증이 성공하게 되면 이 부분을 통해 SecurityContextHolder 에 인증정보를 Set 해주게 된다.
로그인 처리가 되면 SecurityContextPersistenceFilter 에서 인증정보를 사용하고, 다시 Finally 에서
비워주게 된다.
→ 즉 Session 에 넣어논 로그인 인증 정보를 불러와서 사용하고 비워준다. (매 Request 마다 인증을 한다.)
세션이 초기화되면 로그인 인증정보를 못 갖고와 사용할 수 없게 된다.
'SpringFrameWork > SpringSecurity' 카테고리의 다른 글
[SpringSecurity #07] AccessDecisionManager (0) | 2020.09.28 |
---|---|
[SpringSecurity #06] 스프링 시큐리티 Filter와 FilterChainProxy (0) | 2020.09.27 |
[SpringSecurity #04] SecurityContextHolder 와 Authentication (0) | 2020.09.21 |
[SpringSecurity #03] 스프링 시큐리티 테스트 코드 작성 (0) | 2020.09.20 |
[SpringSecurity #02] 스프링 시큐리티 JPA 연동 (0) | 2020.09.20 |