springframework/시작하자SpringSecurity

24.SpringSecurity 필터, 아키텍쳐 정리

Jungsoomin :) 2020. 9. 23. 01:41

Spring Security Initalization

 

2개의 WebSecurityConfigurerAdapter 상속클래스가 있다고 가정한다.

  1. 설정클래스에서 정의한 여러 API 들을 정의

  2. API에 맞는 클래스에서 Filter Type Bean을 생성

  3. Filter Type Bean 들을 생성하는 클래스는 HttpSecurity ( 각각의 설정클래스의 Filter Type Bean 명단SecurityFilterChainFilters 필드에 저장 되는 것 기억 )

  4. HttpSecurityFilter Type Bean(Filters) 들은 WebSecurity 객체에 저장

  5. WebSecurityFilterChainProxy 객체 생성FilterChainProxy의 생성자에 SecurityFilterChain을 전달

  6. FilterChainProxy설정클래스의 API에 맞는 Filters 보유 중.

  7. DelegatingFilterProxy Servlet Filter로 초기화시 자신의 id 와 같은 "springSecurityFilterChain" id 와 같은 Bean을 찾음. 

  8. DelegatingFilterProxy"springSecurityFilterChain" 의 id 를 가진 Bean에게 요청을 위임하게 됨. 즉 FilterChainProxy에게 요청을 위임


SpringSecurity Filter Structure

 

인증시도 , 자원접근 의 2가지로 가정

 

  • 인증시도

  1. Client의 인증시도 : formLogin()

  2. SecurityContextPersistenceFilter 작동

  3. SecurityContextPersistenceFilterHttpSessionSecurityContextRepository 작동

  4. HttpSessionSecurityContextRepositorySecurityContext 를 생성하고 Session에 저장. (이후 HttpSessionSecurityContextRepository Session에 저장된 SecurityContext저장, 조회하고 참조하는 역할을 함)

  5. SecurityContextPersistenceFilter loadContext()Session에 저장된 SecurityContext가 저장되어 있는지 확인 ( 처음 인증시를 가정 중)

  6. create SecurityContext새로운 SecurityContext 생성 ( 처음 인증 시나 익명 사용자의 경우 ) 후 SecurityContextHolder 에 저장 후 Chain

  7. LogoutFilterAntRequestMatcher에 맞지않기 때문에 Chain

  8. UsernamePasswordAuthenticationFilter 작동

  9. UsernamePasswordAuthentiationFilterAuthetication 객체를 생성하여 username , password 저장 

  10. UsernamePasswordAuthenticationFilter Authentication 객체를 매개 값으로 AuthenticationManager(ProviderManager) 를 호출

  11. AuthenticationManager(ProviderManager)는 AuthenticationProvider(DaoAuthenticationProvider, RememeberMeAuthenticationProvider, OauthAuthenticationProvider..) 를 호출하여 실질적 인증 검사시작

  12. AuthenticaionProvider 구현체는 UserDetailsService등을 이용하여 인증작업 진행

  13. AuthenticatiomProvider의 인증 과정을 통과하고 만들어낸 최종 AuthenticaionToken AuthenticationManager > UsernamePasswordAuthenticationFilter 로 반환

  14. UsernamePasswordAuthenticationFilter SecurityContextHolder  에 있는 ThreadLocalSecurityContext 안에 최종 AuthenticationToken 저장 ( SecurityContextHolderSecurityContext는 SecurityContextPersistenceFilter 에서 만들어낸 SecurityContext 객체를 참조한 것)

  15. UsernamePasswordAuthenticationFilter 후속처리를 위해 SessionManagementFilter 작동

  16. 세션 동시 제어를 위해 ConcurrentSessionControlAuthenticationStrategy 호출

  17. ConcurrentSessionControlAuthenticationStrategy 에서 이전사용자 만료 전략일 경우 이전 Session.exprieNow(), 현재 사용자 접근 차단 전략일 경우 SessionAuthenticationException 발생

  18. 세선 고정 보호를 위해 ChangeSessionIdAuthenticaionStrategy 호출

  19. ChangeSessionIdAuthenticationStrategy 에 의해 새로운 JSESSIONID 생성

  20. Session 등록을 위해 RegisterSessionAuthenticationStrategy 호출

  21. RegisterSessionAuthenticationStrategy 에 의해 새로운 Session이 등록

  22. AuthenticationSucessHandler 동작로그인 완료 페이지로 이동할 때에 SecurityContextPersistenceFilter 가 작동

  23. SecurityContextPersistenceFilterSession에 최종적인 SecurityContext를 저장, SecurityContextPersistenceFilterSecurityContextHolder를 비움(.clear())


  • 인증 후 자원 접근 시도
  1. DelegatingFilterProxy가 요청을 받아 FilterChainProxy에 위임 

  2. FilterChainProxy는 가지고 있는 Filter Type Bean 을 이용해 인증, 인가작업 실시

  3. SecurityContextPersistenceFilter가 Client 의 SessionSecurityContext가 있는 지 검사.(Session에 SecurityContext 존재 상태) SessionSecurityContext가 존재하므로 새로운 SecurityContext는 생성하지 않고 Chain

  4. LogoutFilterAntRequestMatcher 에 맞지않으므로 Chain

  5. UsernamePasswordAuthenticationFilterAntRequestMatcher에 맞지 않으므로 Chain

  6. ConcurrentSessionFilter(동시 세션 제어) 가 Client 의 계정으로 인증을 받은 적이 .maximumSessions()이하이므로 Chain

  7. RemeberMeAuthenticationFilter 의 작동 조건은 Client SessionAuthentication 객체가 null일 경우임.(Authentication 객체가 null일 경우 Remeber-Me Cookie가 존재시 인증처리시도SessionSecurityContextAuthenticaion이 존재하므로 Chain

  8. AnonymousAuthenticationFilter 의 작동 조건Client SessionAuthentication 객체가 null일 경우임.(Authentication 객체가 null일 경우 AnonymousAuthenticationToken을 만들고 SecurityContextHolderSecurityContext에 저장) SecurityContextAuthenticaion이 존재하므로 Chain

  9. SessionManagermentFilter 의 동작조건은 ClientSessionSecurityContext가 없는 경우 이므로 Chain

  10. ExceptionTranslationFilter 가 작동

  11. ExceptionTranslationFilter Try-Catch 문으로 감싼 chain.doFilter 작동

  12. FilterSecurityInterceptor 작동

  13. FilterSecurityInterceptor 사용자의 SecurityContextAuthentication객체가 있는지 확인, 없다면 AuthenticationException 발생 (이후 ExceptionTranslationFilter > AutheticaionEntryPoint)

  14. Authention 객체가 있을경우 SecurityMatadataSource를 호출하여 경로에 맞는 권한 정보 도출

  15. 도출된 권한 정보가 없다면 자원 접근

  16. 도출된 권한 정보가 있다면 AcessDesicionManager 호출

  17. AcessDesicionManager  Client의 정보를 들을 가지고 AccessDesicionVotor 클래스들을 호출

  18. AccessDesicionVotor 심사결과를 토대로 AccessDecisionManagerAcessDeninedException을 발생하거나 접근을 허가


  • 이전 계정 만료 전략의 경우 이전 계정의 자원 접근 시도
  1. ConcurrentSessionFilter 작동

  2. ConcurrentSessionFilter 에서 SessionManagementFilter에서 만료시킨 Session이있나 확인 : isExpired()

  3. SessionManagementFilter 만료시킨 Session이 있을 경우 오류 메시지를 호출, Logout 처리