[데브코스] Spring Security - 1
Updated: Categories: TILW15D2 - Spring Security 기본구조 / FilterChainProxy에 대해 알아보자.
Spring Security Architecture
기본 구조

- Spring Security는 웹에서의 요청을 받으면 가장 먼저!! 인증과 인가를 수행한다.
    
- 그 이후 Servlet에 전달하게됨.
 
 - AuthenticationManager : 사용자 인증 관련 처리
 - AccessDecisionManager : 사용자가 보호받는 리소스에 접근할 수 있는 적절한 권한이 있는지 확인
 
FilterChainProxy
- Spring Security는 서블릿 필터 
javax.servlet.Filter의 구현체로 동작한다. @EnableWebSecurity어노테이션과 함께WebSecurityConfigurerAdapter추상 클래스를 상속받아 구현함- 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
        
- 웹 요청은 모든 필터를 통과하게 되지만, 모든 필터가 동작하는 것은 아님
 - 각 필터는 웹 요청에 따라 동작 여부를 결정할 수 있고, 동작할 필요가 없다면 다음 필터로 웹 요청을 즉시 넘김
 
 - 요청을 처리하고 응답을 반환하면 필터 체인 호출 스택은 모든 필터에 대해 역순으로 진행
 - 보통 springSecurityFilterChain 이라는 이름으로 Bean 등록됨
 
- 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
        
 

- Spring Security는 Filter를 잘 이해하고 사용할 수 있어야 함!
    
- 참고 : 공식문서
 
 
필터 종류
- 필터 흐름에 따라 순서가 있다. 주요필터들을 정리해보자면..
 
| 필터 | 설명 | 
|---|---|
ChannelProcessingFilter | 
      웹 요청이 어떤 프로토콜로 (http 또는 https) 전달되어야 하는지 처리 | 
SecurityContextPersistenceFilter | 
      SecurityContextRepository를 통해 SecurityContext를 Load/Save 처리 | 
LogoutFilter | 
      로그아웃 URL로 요청을 감시하여 매칭되는 요청이 있으면 해당 사용자를 로그아웃 시킴 | 
UsernamePasswordAuthenticationFilter | 
      ID/비밀번호 기반 Form 인증 요청 URL(기본값: /login) 을 감시하여 사용자를 인증함 | 
DefaultLoginPageGeneratingFilter | 
      로그인을 수행하는데 필요한 HTML을 생성함 | 
RequestCacheAwareFilter | 
      로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청으로 이동하기 위해 사용됨 | 
SecurityContextHolderAwareRequestFilter | 
      서블릿 3 API 지원을 위해 HttpServletRequest를 HttpServletRequestWrapper 하위 클래스로 감쌈 | 
    
RememberMeAuthenticationFilter | 
      요청의 일부로 remeber-me 쿠키 제공 여부를 확인하고, 쿠키가 있으면 사용자 인증을 시도함 | 
AnonymousAuthenticationFilter | 
      해당 인증 필터에 도달할때까지 사용자가 아직 인증되지 않았다면, 익명 사용자로 처리하도록 함 | 
ExceptionTranslationFilter | 
      요청을 처리하는 도중 발생할 수 있는 예외에 대한 라우팅과 위임을 처리함 | 
FilterSecurityInterceptor | 
      접근 권한 확인을 위해 요청을 AccessDecisionManager로 위임 | 
ChannelProcessingFilter
- ChannelProcessingFilter 설정을 통해 HTTPS 채널을 통해 처리해야 하는 웹 요청을 정의할 수 있음
 - 실제적인 처리를 ChannelDecisionManager 클래스로 위임함
 
AnonymousAuthenticationFilter
- 비교적 필터체인 마지막에 동작하는 필터
 - 해당 필터에 요청이 도달할때까지 사용자가 인증되지 않았다면, 사용자를 null 대신 Anonymous 인증 타입으로 표현
    
name = anonymousUser으로 처리한다
 
AnonymousAuthenticationFilter class

- 인증이 null이면 default값으로 정보를 넣어주는것을 확인할 수 있음
 - 아래처럼 이름과 권한을 커스텀할 수 있다.
 
http.anonymous()
    .principal(익명유저 이름 설정)
    .authorities(익명유저 권한 설정)
ExceptionTranslationFilter
FilterSecurityInterceptor바로 위에 위치하며,FilterSecurityInterceptor실행 중 발생할 수 있는 예외를 잡고 처리함ExceptionTranslationFilter는 필터체인 실행스택에서 자기 아래에 오는 필터들에서 발생하는 예외들에 대해서만 처리할 수 있다. (따라서 커스텀 필터를 추가해야 하는 경우 커스텀 필터를 적당한 위치에 두어야 한다.)

AuthenticationException: 인증 관련 예외이며, 사용자를 로그인 페이지로 보냄AccessDeniedException: 권한 관련 예외,AccessDecisionManager에 의해 접근 거부가 발생했을 때 접근 거부 페이지를 보여주거나 사용자를 로그인 페이지로 보냄AuthenticationEntryPoint: 사용자를 정해진 페이지로 포워딩해주는 역할
커스텀
- AccessDeniedHandler를 리턴하는 메소드를 Bean으로 띄워 커스텀이 가능하다
 
AccessDeniedHandler 작성
@Bean
public AccessDeniedHandler customAccessDeniedHandler() {
    return (request, response, e) -> {
        ...
    };
}
exceptionHandling 필터 작성
http.exceptionHandling()
    .accessDeniedHandler(customAccessDeniedHandler())
RequestCacheAwareFilter
- 로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청으로 이동하기 위해 사용되는 필터
 - 이게 무슨 말일까? 예시를 통해 이해해보자.
 
예시
- 어떤 익명 사용자가 권한이 필요한 페이지에 접근하려 한다면? 아래와 같은 일이 일어난다.
 

- 페이지에 접근 권한이 없으므로 
ExceptionTranslationFilter의AccessDenied에 걸리게 된다. RequestCacheAwareFilter에 의해 해당 페이지 요청은 캐시에 저장된다.- 마지막으로 default 설정인 
/login으로 리다이렉트 시킴. 
- 그리고 사용자가 리다이렉트된 페이지에서 로그인한다면?
    
- 로그인 후 default 설정은 루트 url 
/로 이동시키는 것이지만, 맨 처음 요청했던 페이지로 이동된다. - 이를 가능하게 하는것이 
RequestCacheAwareFilter의 기능! 
 - 로그인 후 default 설정은 루트 url 
 
