Spring Security - Authentication

Kyojun Jin·2024년 5월 13일
0

Spring

목록 보기
4/12

이전 글 Spring Security 아키텍쳐를 이해했다면 스프링 시큐리티의 인증 방식은 쉽게 이해할 수 있다.

SecurityContext and its holder

스프링 시큐리티 인증 모델의 중심에는 SecurityContextHolder가 있다. 이는 SecurityContext를 가진다. 스프링 시큐리티는 인증할 때 이 정보를 활용한다.

SecurityContextAuthentication을 가진다. 이는 principal, credentials, authorities 를 가지고 있다. principal은 사용자를 식별한다. credentials은 주로 비밀번호를 가리킨다. 사용자 인증 후 지워진다. authorities는 권한이다.

Authentication

Authentication는 두 가지 용도로 사용된다.
1. 인증된 사용자의 현재 인증 정보(principal, credentials, authorieis)를 저장. (SecurityContext가 가지고 있다.)
2. 1번의 Authentication을 얻기 위해, Filter가 사용자가 입력한 데이터를 통해 사용자를 확인해보기 위해 사용. 이 시기에는 SecurityContext의 Authentication은 False이다. AuthenticationManager를 통해 실제 Authentication을 얻어서 SecurityContext에 넣어주게 된다. (이때부터 1번 용도)

GrantedAuthority

Authentication.getAuthorities()으로 얻을 수 있다. 이는 GrantedAuthority 객체들의 Collection이다. 이들은 principal이 얻은 실제 권한들이다. 주로 ROLE_ADMINISTRATOR나 ROLE_HR_SUPERVISOR 같은 'roles'이다.

GrantedAuthority는 application-wide 권한이다. 특정 도메인에 관한 권한이 아니다. 따라서 이 권한을 '직원번호 54번'에 대한 권한으로 사용할 수 없다. 그런 권한 수천개가 있다면 메모리가 부족해지거나 사용자 인증하는데 시간이 엄청 걸릴 것이다. 스프링 시큐리티는 흔한 요구사항을 처리할 수 있다.

AuthenticationManager

AuthenticationManager는 스프링 시큐리티의 필터의 인증 작업을 규정하는 API이다. 이 작업을 통해 Authentication이 Filter(= SecurityFilter를 거쳐 DelegatingFilterProxy)를 통해 반환되어 Controller의 SecurityContextHolder에 저장된다.

ProviderManager

ProviderManager는 AuthenticationManager 의 구현체로 주로 사용된다. 이는 AuthenticationProvider들에게 인증 작업을 위임한다. Provider들은 성공, 실패하거나 혹은 결정을 못 내려서 다음 Provider에게 맡긴다는 것을 보여야 한다. 모든 Provider가 인증을 못한다면 인증은 실패하고 ProviderNotFoundException이 발생한다. 이는 ProviderManager가 Authentication에 맞는 Prover를 못 찾겠다는 것을 보이는 특별한 AuthenticationException이다.

각각의 AuthenticationProvider들은 특정한 인증 작업을 시도한다. 예를 들어 어떤 Provider는 사용자 이름과 비밀번호를 검사할 수도 있고, 어떤 건 SAML assertion을 인증할 수 있다. 각각의 Provider가 그들만의 인증 작업을 하고 있기 때문에, AuthenticationManager 빈 하나만 노출시키면서 여러 유형의 인증 작업을 할 수 있다.

AuthenticationManager는 여러 ProviderManager 를 자식으로 둘 수 있다. 여러 SecurityFilterChain의 몇몇 인증 작업이 공통적인 시나리오에서 흔히 보인다.

ProviderManager 는 기본적으로 Provider들이 주는 Authentication 객체 내 민감한 credential 정보를 지운다.

AuthenticationProvider

AuthenticationProvider는 특정 유형의 인증 작업을 진행한다. 예를 들어 DaoAuthenticationProvider는 사용자 이름/비밀번호에 기반한 인증을 한다. JwtAuthenticationProvider 는 JWT 토큰으로 인증을 한다.

AuthenticationEntryPoint 로 자격 증명 요청하기

AuthenticationEntryPoint을 구현해서 사용자를 로그인 페이지로 리디렉션해서 WWW-Authenticate 헤더를 가져오거나 다른 작업을 취할 수 있다.

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter는 사용자의 자격 증명을 인증하기 위한 기본 Filter이다. 이게 인증되기 전에 AuthenticationEntryPoint를 사용해서 자격증명을 요청하기도 한다.

스프링 시큐리티의 인증 절차는 다음과 같다.

  1. 사용자가 인증이 필요한 요청 (HttpServletRequest)을 보낸다.
  2. DelegatingFilterProxy가 필터링된 요청을 서버로 보내려고 한다.
    FilterChainProxy가 적절한 SecurityFilterChain을 골라 이 Filter들에게 작업을 위임한다.
  3. 적절한 SecurityFilterChain이 선택되어서 Security Filter 내 작업들을 진행한다.
  4. 그러던 중 AbstractAuthenticationProcessingFilter가 동작한다.
  5. 이 필터는 인증을 요하는 필터, 서브클래스마다의 Authentication 정보를 생성한다.
  6. Authentication이 AuthenticationManager에 입력된다.
  7. AuthenticationManager는 인터페이스로, ProviderManager로 구현할 수 있다. 이는 AuthenticationProvider들의 리스트에게 인증 작업을 위임한다.
  8. AuthenticationProvider가 각각 특정 유형의 인증 작업을 시도한다.
  9. 인증 결과를 전달받는다.
  10. 실패햇을 시
    1. SecurityContextHolder 가 지워진다.
    2. RememberMeServices.loginFail가 참조된다. 설정된 적 없으면 아무런 동작하지 않는다.
    3. AuthenticationFailureHandler가 참조된다.
  11. 성공했을 시
    1. SessionAuthenticationStrategy 에 새 로그인을 알린다.
    2. SecurityContextHolder에 Authentication을 등록한다. 나중에 또 요청할 것을 대비해서 SecurityContext를 저장하려면 SecurityContextRepository#saveContext을 호출해야 한다. SecurityContextHolderFilter 참조.
    3. RememberMeServices.loginSuccess이 참조된다.
    4. ApplicationEventPublisher 가 InteractiveAuthenticationSuccessEvent를 Publish 한다.
    5. AuthenticationSuccessHandler가 참조된다.

0개의 댓글