[Spring Security] 인증 아키텍처

🔐 스프링 시큐리티

  1. 기본 용어
  2. 아키텍처
  3. 인증 아키텍처
  4. 인증 영속성
  5. 예외 처리
  6. 폼 기반 인증
  7. 기억하기 인증
  8. 인증 간 요청 저장
  9. 인가 아키텍처
  10. 요청 수준 인가 & 메소드 수준 인가

👽 Authentication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.springframework.security.core;

import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;

public interface Authentication extends Principal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    Object getCredentials();

    Object getDetails();

    Object getPrincipal();

    boolean isAuthenticated();

    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
  • principal: 인증 주체를 의미하며 인증 요청의 경우 사용자 이름(아이디)을, 인증 후에는 UserDetails 타입의 객체가 될 수 있다.
  • credentials: 인증 주체가 올바른 것을 증명하는 자격 증명으로서 대개 비밀번호를 의미한다.

🍕 SecurityContextHolder

SecurityContextHolder

SecurityContextHolder 는 현재 인증된 사용자의 정보를 SecurityContext 객체에 저장하고 있다. 인증 주체(principal)에 대한 정보를 얻으려면 SecurityContextHolder 에 접근하면 된다. 아래는 SecurityContextHolder 를 통해 인증 정보를 조회하는 방법이다.

1
2
3
4
5
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

기본적으로 SecurityContextHolderThreadLocal 을 사용해 보안 컨텍스트를 저장한다. ThreadLocal 을 사용하면 각 스레드가 독립적인 SecurityContext 를 가지게 되며, 동일한 스레드 내의 메서드에서 SecurityContext 에 접근할 수 있다.
그러나 ThreadLocal 은 스레드가 종료되면 자동으로 정리되지 않으므로 애플리케이션이 스레드를 재사용하거나 스레드 풀이 있는 환경에서는 주의를 기울여야 한다. FilterChainProxySecurityContext 가 항상 적절히 지워지도록 보장해 이러한 문제를 방지한다.

SecurityContextHolderSecurityContext 를 저장하는 다양한 전략을 제공한다. SecurityContextHolder.MODE_THREADLOCAL 은 기본값으로 각 스레드가 독립적인 보안 컨텍스트를 가지며 대부분의 서버 환경에 적합하다. 이외에도 MODE_INHERITABLETHREADLOCAL(하위 스레드가 부모 스레드의 보안 컨텍스트를 상속 받음)과 MODE_GLOBAL(모든 스레드가 공유하는 전역 보안 컨텍스트) 전략이 있으며 필요에 따라 선택할 수 있다.


🍅 SecurityContext

SecurityContextHolder 를 통해 SecurityContext 를 조회할 수 있으며, 이 SecurityContext 는 현재 인증된 사용자의 Authentication 객체를 포함하고 있다.


👒 AuthenticationManager

AuthenticationManager 는 필터가 전달한 인증 정보를 바탕으로 인증을 수행하고, 인증 결과를 반환한다. `AuthenticationManager` 의 호출 후, 반환된 [`Authentication`](#-authentication) 객체가 [`SecurityContextHolder`](#-securitycontextholder) 에 설정된다.
주로 사용하는 구현체는 ProviderManager 다.


🐝 ProviderManager

ProviderManagerAuthenticationManager 의 구현체다. ProviderManagerAuthenticationProvider 목록 중에서 인증 처리 요건에 맞는 적절한 AuthenticationProvider 를 찾아 인증 처리를 위임한다. AuthenticationProvider 인스턴스 중 아무도 인증할 수 없는 경우, ProviderMangerProviderNotFoundException 을 발생시킨다.

ProviderManager

또한 ProviderManager 는 선택적으로 부모 AuthenticationManager 를 구성할 수 있는데, 이 부모는 AuthenticationProvider 중 아무도 인증을 수행할 수 없는 경우에 참조된다. 부모는 모든 유형의 AuthenticationManager 가 될 수 있지만, 일반적으로 ProviderManager 의 인스턴스다.

ProviderManager 부모


🍄 AuthenticationProvider

AuthenticationProvider 는 특정 유행의 인증을 수행하는데 사용된다. 예를 들어 DaoAuthenticationProvider 는 사용자 이름과 비밀번호 기반 인증을 지원하며, JwtAuthenticationProvider 는 JWT 토큰 인증을 지원한다. ProviderManager 에는 여러 개의 AuthenticationProvider 인스턴스를 주입할 수 있다.


🌊 인증 흐름(Authentication Flow)

flow

  1. 사용자가 자격 증명을 제출하면, AbstractAuthenticationProcessingFilterHttpServletRequest 에서 Authentication 객체를 생성하여 인증한다. 생성되는 Authentication 의 유형은 AbstractAuthenticationProcessingFilter 의 하위 클래스에 따라 달라진다. 예를 들어, UsernamePasswordAuthenticationFilterHttpServletRequest 에서 제출된 사용자 이름과 비밀번호를 바탕으로 UsernamePasswordAuthenticationToken 을 생성한다.
  2. 그런 다음, 생성된 Authentication 객체를 인증을 위해 AuthenticationManager 에 전달한다.
  3. 인증이 실패하면 다음과 같은 처리가 이루어진다.
    • SecurityContextHolder 가 비워진다.
    • RememberMeServices.loginFail 이 호출된다. “Remember Me”가 구성되지 않은 경우, 이 호출은 무시된다.
    • AuthenticationFailureHandler 가 호출된다.
  4. 인증이 성공하면 다음과 같은 처리가 이루어진다.
    • SessionAuthenticationStrategy 가 새로운 로그인을 알린다.
    • AuthenticationSecurityContextHolder 에 설정된다. 나중에 SecurityContext 를 저장해 향후 요청에서 자동으로 설정할 수 있도록 하려면 SecurityContextRepository#saveContext 를 명시적으로 호출해야 한다.
    • RememberMeServices.loginSuccess 가 호출된다. “Remember Me”가 구성되지 않은 경우, 이 호출은 무시된다.
    • ApplicationEventPublisherInteractiveAuthenticationSuccessEvent 를 게시한다.
    • AuthenticationSuccessHandler 가 호출된다.

참고

Leave a comment