사용자의 인증처리를 담당하는 Authentication Manager
사용ㅇ자가 적절한 권한을 가지고 있는지 확인하는지 Acess Decision Manager
로 구성되어 있다. 사용자가 요청을 보냈을떄 사용자를 인증하고 인증된 사용자가 리소스에 접근하는데 적절한 권한이 있는지 확인한 후 적절한 권한이 없었다면 Acess Decision Manager 에서 403 과 같은 응답을 한다. 사용자가 적절한 권한을 가지고 있었으면 정상적으로 요청한 리소스에 대해 응담이 내려가게 됨
스프링시큐리티는 결국 서블릿필터의 목록이다.
서블릿 필터를 구현하고 있는 필터구현체들의 집합
사용자의 웹 요청은 스프링시큐리티의 서블릿 필터 목록으로 전달이 되고 처리가 이러우지게 됨
서블릿필터목록을 필터체인 프록시라고 부름
사용자의 웹요청은 필터체인 프록시에 들어오게되고 필터들을 순차적으로 통과
-delegatingFilterProxy :뭔가르 위임하기 위한 필터
요청을 받아 그 요청을 delegate로 전달
스프링큐리티의 필터체인 목록을 delegate로 지정하는 delegateFilterProxy를 만들고 있음
사용자의 웹요청은 delegatingFilterProxy에 의해서 filterchainProxy에 전달이 됐고, filterchainProxy에서 스프링 니큐리티 필터목록을 가지고와 사용자의 웹요청을 필터목록에 의해 처리하게 댐
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// Lazily initialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
String targetBeanName = getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
Filter delegate = wac.getBean(targetBeanName, Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
delegate.doFilter(request, response, filterChain);
}
FilterSecurityInterceptor 에서 접근거부가 되어 예외가 발생 하고 ExceptionTranslationFilter가 그 예외를 catch한다.
실제로 ExceptionTranslationFilter가 예외를 발생하는지 보기위해 breakPoint를 두고 권한이 필요한 /me 페이지에 접속한다.
예상대로 아직 로그인 하기 전이기 때문에 권한이 없어 AccessDeniedException이 발생하는 것을 볼 수 있다. 이 ExceptionTranslationFilterd을 더 자세하게 살펴 보도록 하자
예외 타입에 따라 처리하는 방식이 나누어져 있고 아까 발생한 AccessDeniedException을 다루는 handleAccessDeniedException을 들어가본다.
handleAccessDeniedException에서는 먼저 익명인지 확인하고 그 여부에 따라 다르게 동작한다. 주의해서 봐야할 부분은 sendStartAuthenticationdl 인데 , 우리가 실제로 /me 페이지에 접속하면 권한이 없기때문에 로그인 페이지로 리다이렉션 되는것을 확인 할 수 있다. 즉 sendStartAuthentication 는 사용자를 로그인 페이지로 리다이렉션하는 역할을 하는 것이다.
sendStartAuthentication에서는 원래 접속할랐던 me 페이지를 savedRequset라는 객체를 만들어서 저장 후 리다이랙션하는 것을 확인 할 수 있다.
https 의 default 포트인 443으로 변경
ssl 생성시 만들었던 alias
maven을 reload하고 프로젝트를 실행시키면 443포트로 뜨는 것과 링크 접속시 인증서에 대한 정보를 확인할 수 있다.
현재요청을 hppt와 https 중에서 어떤걸로 처리하는지 결정하는 부분인
channelDecisionManager를 더 자세히 살펴보도록 하자
먼저, WebSecurityConfigure에 설정 정보를 추가해주고
channelDecisionManager 에 breakPoint를 걸고 디버깅을 해보면
reauestMap에 우리가 설정파일에 적어놨던 any request 정보가 담겨 있는것을 확인할 수 있다.
설정정보를 변경후에 다시 디버깅 해보면 마찬가지로 변경한 정보가 담겨 있는것을 확인 할 수 있다.
channelProcessingFilter에 있는 channelDecisionManager을 마찬가지로 디버깅해보면 channelProcessors에 InsecureChannelProcessor과 SecureChannelProcessor에 대한 정보가 담겨 있는 것을 확인 할 수 있다.
SecureChannelProcessor는 현재 요청이 secure(https인지 아닌지) 여부에 따라 아닐경우 if문이 실행되어 리다이렉션이 발생 했을 것이다.
우리는 이미 ssl을 이용해 secure 되기때문에 if문이 실행되지는 않았다.