<Spring Security> 스프링 시큐리티 필터 및 아키텍처 정리

라모스·2022년 3월 22일
0

Spring Security🔐

목록 보기
5/6
post-thumbnail

여러 케이스별 Spring Security Logic

공통 로직 - 초기화

  • 사용자가 설정 클래스에서 생성 및 설정한 여러 SecurityConfig 클래스로 HttpSecurity에서 Filter를 생성하여 WebSecurity에 전달한다.
  • WebSecurityFilterChainProxy 객체에 Bean 객체를 생성하여 생성자로 자신이 가지고 있는 Filter 목록을 전달한다.
  • DelegatingFilterProxyspringSecurityFilterChain라는 이름의 Bean을 가진 Bean Class를 찾는데 그게 FilterChainProxy 에게 전달하여 요청을 위임한다.

로그인 - (인증 전) 인증 시도

SecurityContextPersistenceFilter

  1. DelegatingFilterProxy에서 FilterChainProxy에게 인증 요청 위임
  2. SecurityContextPersistanceFilter에서 loadContext 함수를 호출해 SecurityContext가 있는지 확인한다.
    → 내부적으로 HttpSessionSecurityContextRepository 클래스가 있고, SecurityContext의 생성, 저장, 조회, 참조를 하는 클래스
  3. 새로운 SecurityContext를 저장해서 SecurityContextHolder에 저장한 뒤 다음 필터로 이동한다.

LogoutFilter

  1. Logout 요청을 한 것이 아니므로 다음 필터로 패스한다.

UsernamePasswordAuthenticationFilter

  1. 전달받은 Username, Password를 가지고 인증 객체(Authentication)을 만든다.
  2. AuthenticationManager 에게 인증 처리 위임
  3. AuthenticationManagerAuthenticationProvider에게 실제 인증 처리를 위임한다.
  4. AuthenticationProviderUserDetailsService를 활용해서 아이디와 패스워드를 검증한다.
  5. 인증에 성공했다면, SecurityContextHolder안에 SecurityContext에 인증에 성공한 인증 객체(Authentication)를 생성 및 저장한다.
    SecurityContextSecurityContextPersistenceFilter에서 만들어진 SecurityContext를 참조한 것이다.
  6. 인증 후 후속 처리를 동시에 하게 되는데, 이 과정이 SessionManagementFilter 안의 3가지 과정이다.
  • ConcurrentSession에서 동시적 세션 체크를 하는데, 두 가지 전략이 있다. 하지만, 이 상황에선 첫 로그인이기에 패스한다.
    • 이전 사용자 세션 만료 전략: session.expireNow로 이전 사용자의 세션을 만료시킨다.
    • 현재 사용자 인증 시도 차단 전략: SessionAuthenticationException 예외를 발생시켜 인증을 차단한다.
  • SessionFixation (세션 고정 보호)에서 인증에 성공한 시점에서 새롭게 쿠키를 발급한다.
  • 이 사용자 정보로 SessionInfo를 만들어 저장한다.
  1. 인증 성공 후 후처리 로직을 수행하는데, 이 시점에서 동시에 수행되는 로직이 있다.
  • SecurityContextPersistenceFilter가 최종적으로 Session에 인증 객체(Authentication)를 담은 SecurityContext를 저장한다.
  • SecurityContext를 Clear 해준다.
  • 정의된 인증 성공 후 후처리 페이지로 이동한다. (ex. Main 페이지 이동)

인증 후 특정 페이지 이동(자원 요청)

SecurityContextPersistenceFilter

  1. loadContext로 Session에서 SecurityContext를 꺼내온다.
  2. SecurityContextHolder에서 꺼내 온 SecurityContext를 저장
  3. 다음 필터로 이동한다.

LogoutFilter, UsernamePasswordAuthenticationFilter

이 과정에선 패스한다.

ConcurrentSessionFilter

  1. 최소 두 명 이상이 동일한 계정으로 접속을 시도하는 경우에 동작한다.
  2. Session이 만료되었는지 isExpired를 통해 확인
  3. 만료되지 않았기 때문에 다음 필터로 이동한다.

RememberMeAuthenticationFilter

현재 사용자가 세션이 만료되었거나 무효화되어 세션 내부의 인증객체가 비어있을 경우 동작한다.
1. 사용자의 요청 정보(header)에 remember-me cookie값을 확인한다.
2. 없으면 동작하지 않는다.

AnonymousAuthenticationFilter

사용자가 인증시 인증객체도 없고 권한 없이 특정 자원에 접근 시도시 동작한다.
(위 과정에선 인증되어있는 상태이기 때문에 패스한다.)

SessionManagementFilter

Session에 SecurityContext가 없는 경우나 Session이 없는 동작한다.
(위 과정에선 인증 후 접근이기 때문에 다음 필터로 넘어간다.)

ExceptionTranslationFilter

Try-Catch로 다음 필터 동작을 감싸서 FilterSecurityInterceptor 수행 중 일어나는 예외를 받아 동작한다.

FilterSecurityInterceptor

AccessDecisionVoter에게 인가 처리를 위임한다.

  • 인증 객체가 없을 경우, AuthenticationException이 발생하여 ExceptionTranslationFilter에게 전달한다.
  • 접근이 인가되지 않을 경우, AccessDeniedException이 발생하여 ExceptionTranslationFilter에게 전달한다.

동일 계정 다른 기기 중복 로그인 - 최대 1개 세션 허용 정책

SecurityContextPersistenceFilter

첫 번째 인증 사용자의 로직과 동일하게 수행한다.

LogoutFilter

인증 시도이기 때문에 다음 필터로 패스한다.

UsernamePasswordAuthenticationFilter

  1. 인증 성공 후 SecurityContextHolder안에 인증 객체(Authentication)가 저장된 SecurityContext를 저장
  2. ConcurrentSession에서 정책을 확인한다.
  • 현재 사용자 인증 시도 차단 전략: SessionAuthenticationException 예외를 발생시켜 인증 처리 실패.
  • 이전 사용자 세션 만료 전략: session.expireNow로 이전 사용자의 세션을 만료시킨 뒤 자신의 인증객체를 저장한다.

이전 사용자 세션 만료 정책일 경우 이후부터는 기존 인증 요청과 동일하게 로직을 수행한다.

동일 계정이 다른 기기에서 로그인 되어 세션이 만료된 계정에서 자원 요청(Request)

  • ConcurrentSessionFilter
  1. session.isExpired를 통해 현재 세션이 만료되었는지 확인
  2. 만료되었기 때문에 Logout 로직 수행
  3. error 응답 후 다음 필터 수행 없이 종료

References

profile
Step by step goes a long way.

0개의 댓글