Spring Security ‐ Servlet Authentication Architecture - taeyun-ham/andalos GitHub Wiki

Authentication

Spring Security는 인증에 대한 포괄적인 지원을 제공합니다. 전반적인 서블릿 인증 아키텍처에 대해 논의하는 것부터 시작합니다. 예상할 수 있듯이 이 섹션은 아키텍처가 구체적인 흐름에 어떻게 적용되는지에 대한 많은 논의 없이 아키텍처를 설명하는 보다 추상적입니다.

원하는 경우 사용자가 인증할 수 있는 구체적인 방법은 인증 메커니즘을 참조할 수 있습니다. 이 섹션에서는 인증하려는 특정 방법에 중점을 두고 특정 흐름이 작동하는 방식을 설명하기 위해 아키텍처 섹션을 다시 가리킵니다.

Authentication Mechanisms

  • Username and Password : 사용자 이름/비밀번호로 인증하는 방법
  • OAuth 2.0 Login : OpenID Connect 및 비표준 OAuth 2.0 로그인(예: GitHub)을 사용한 OAuth 2.0 로그인
  • SAML 2.0 Login : SAML 2.0 로그인 중앙 인증 서버(CAS) - 중앙 인증 서버(CAS) 지원
  • Remember Me - 세션 만료 후 사용자를 기억하는 방법
  • JAAS Authentication - JAAS 인증
  • Pre-Authentication Scenarios - SiteMinder 또는 Java EE 보안과 같은 외부 메커니즘으로 인증하지만 일반적인 악용에 대한 인증 및 보호를 위해 여전히 Spring Security를 ​​사용합니다.
  • X509 Authentication - X509 인증

Servlet Authentication Architecture

Servlet Security 확장 : The Big Picture를 확장하여 Servlet 인증에 사용되는 Spring Security의 주요 아키텍처 구성 요소를 설명합니다. 이러한 부분이 어떻게 결합되는지 설명하는 구체적인 흐름이 필요한 경우 Authentication Mechanisms 관련 섹션을 살펴보세요.

  • SecurityContextHolder - SecurityContextHolder는 Spring Security가 인증된 사람에 대한 세부 정보를 저장하는 곳입니다.
  • SecurityContext - SecurityContextHolder 에서 가져오며 현재 인증된 사용자의 인증을 포함합니다.
  • Authentication - 인증을 위해 사용자가 제공한 자격 증명을 제공하기 위해 AuthenticationManager에 대한 입력이거나 SecurityContext의 현재 사용자일 수 있습니다.
  • GrantedAuthority - 인증 시 주체에게 부여되는 권한(예: 역할, 범위 등)
  • AuthenticationManager - Spring Security의 필터가 인증을 수행하는 방법을 정의하는 API입니다. * ProviderManager - 가장 일반적인 AuthenticationManager 구현입니다.
  • AuthenticationProvider - 특정 유형의 인증을 수행하기 위해 ProviderManager에서 사용됩니다.
  • Request Credentials with AuthenticationEntryPoint - 클라이언트에서 자격 증명을 요청하는 데 사용됩니다(예: 로그인 페이지로 리디렉션, WWW-* 인증 응답 전송 등).
  • AbstractAuthenticationProcessingFilter - 인증에 사용되는 기본 필터입니다. 이는 또한 높은 수준의 인증 흐름과 여러 부분이 함께 작동하는 방식에 대한 좋은 아이디어를 제공합니다.

SecurityContextHolder

Spring Security 인증 모델의 핵심은 SecurityContextHolder입니다. 여기에는 SecurityContext가 포함되어 있습니다.

securitycontextholder

SecurityContextHolder는 Spring Security가 인증된 사람에 대한 세부 정보를 저장하는 곳입니다. Spring Security는 SecurityContextHolder가 어떻게 채워지는지 신경 쓰지 않습니다. 값이 포함되어 있으면 현재 인증된 사용자로 사용됩니다.

사용자가 인증되었음을 나타내는 가장 간단한 방법은 SecurityContextHolder를 직접 설정하는 것입니다.

SecurityContext context = SecurityContextHolder.createEmptyContext(); 
Authentication authentication =
    new TestingAuthenticationToken("username", "password", "ROLE_USER"); 
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context); 

현재 인증된 사용자에 접근

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

기본적으로 SecurityContextHolder는 ThreadLocal을 사용하여 이러한 세부 정보를 저장합니다. 즉, SecurityContext가 해당 메서드에 대한 인수로 명시적으로 전달되지 않더라도 동일한 스레드의 메서드에서 항상 SecurityContext를 사용할 수 있습니다. 현재 주체의 요청이 처리된 후 스레드를 지우는 데 주의를 기울이면 이러한 방식으로 ThreadLocal을 사용하는 것이 매우 안전합니다. Spring Security의 FilterChainProxy는 SecurityContext가 항상 지워지는 것을 보장합니다.

SecurityContext

SecurityContext는 SecurityContextHolder에서 가져옵니다. SecurityContext에는 인증 개체가 포함되어 있습니다.

Authentication

Authentication 인터페이스는 Spring Security 내에서 두 가지 주요 목적을 제공합니다.

  • 사용자가 인증을 위해 제공한 자격 증명을 제공하기 위한 AuthenticationManager에 대한 입력입니다. 이 시나리오에서 사용되면 isAuthenticated()는 false를 반환합니다.
  • 현재 인증된 사용자를 나타냅니다. SecurityContext에서 현재 인증을 얻을 수 있습니다.

Authentication 에는 다음이 포함됩니다

  • principal : 사용자를 식별합니다. 사용자 이름/비밀번호로 인증할 때 이는 UserDetails의 인스턴스인 경우가 많습니다.
  • credentials : 비밀번호인 경우가 많습니다. 많은 경우, 이는 유출되지 않도록 사용자가 인증된 후 지워집니다.
  • authorities : GrantedAuthority 인스턴스는 사용자에게 부여되는 상위 수준 권한입니다. 두 가지 예는 역할과 범위입니다.

GrantedAuthority

GrantedAuthority 인스턴스는 사용자에게 부여되는 상위 수준 권한입니다. 두 가지 예는 역할과 범위입니다.

Authentication.getAuthorities() 메소드에서 GrantedAuthority 인스턴스를 얻을 수 있습니다. 이 메소드는 GrantedAuthority 객체의 컬렉션을 제공합니다. GrantedAuthority는 당연히 주체에게 부여되는 권한입니다. 이러한 권한은 일반적으로 ROLE_ADMINISTRATOR 또는 ROLE_HR_SUPERVISOR와 같은 "역할"입니다. 이러한 역할은 나중에 웹 권한 부여, 메소드 권한 부여 및 도메인 객체 권한 부여를 위해 구성됩니다. Spring Security의 다른 부분에서는 이러한 권한을 해석하고 해당 권한이 있을 것으로 기대합니다. 사용자 이름/비밀번호 기반 인증을 사용할 때 GrantedAuthority 인스턴스는 일반적으로 UserDetailsService에 의해 로드됩니다.

일반적으로 GrantedAuthority 개체는 애플리케이션 전체 권한입니다. 이는 특정 도메인 개체에만 국한되지 않습니다. 따라서 Employee 개체 번호 54에 대한 권한을 나타내는 GrantedAuthority가 없을 가능성이 높습니다. 왜냐하면 이러한 권한이 수천 개 있으면 메모리가 빨리 부족해지거나 최소한 응용 프로그램에 오랜 시간이 걸리기 때문입니다. 사용자를 인증하기 위해). 물론 Spring Security는 이러한 공통 요구 사항을 처리하도록 명시적으로 설계되었지만 대신 이 목적을 위해 프로젝트의 도메인 객체 보안 기능을 사용해야 합니다.

AuthenticationManager

AuthenticationManager는 Spring Security의 필터가 인증을 수행하는 방법을 정의하는 API입니다. 반환된 인증은 AuthenticationManager를 호출한 컨트롤러(즉, Spring Security의 필터 인스턴스)에 의해 SecurityContextHolder에 설정됩니다. Spring Security의 필터 인스턴스와 통합하지 않는 경우 SecurityContextHolder를 직접 설정할 수 있으며 AuthenticationManager를 사용할 필요가 없습니다.

AuthenticationManager의 구현은 무엇이든 가능하지만 가장 일반적인 구현체는 ProviderManager입니다.

ProviderManager

ProviderManager는 가장 일반적으로 사용되는 AuthenticationManager 구현체입니다. ProviderManager는 AuthenticationProvider 인스턴스 목록에 위임합니다. 각 AuthenticationProvider에는 인증이 성공해야 하는지, 실패해야 하는지 표시하거나 결정을 내릴 수 없음을 표시하고 하위의 AuthenticationProvider가 결정하도록 허용할 수 있는 기회가 있습니다. 구성된 AuthenticationProvider 인스턴스 중 어느 것도 인증할 수 없는 경우 ProviderNotFoundException과 함께 인증이 실패합니다. 이는 ProviderManager가 전달된 인증 유형을 지원하도록 구성되지 않았음을 나타내는 특수 AuthenticationException입니다.

providermanager

실제로 각 AuthenticationProvider는 특정 유형의 인증을 수행하는 방법을 알고 있습니다. 예를 들어, 한 AuthenticationProvider는 사용자 이름/비밀번호의 유효성을 검사할 수 있고 다른 AuthenticationProvider는 SAML 어설션을 인증할 수 있습니다. 이를 통해 각 AuthenticationProvider는 다양한 유형의 인증을 지원하면서 매우 특정한 유형의 인증을 수행하고 단일 AuthenticationManager Bean만 노출할 수 있습니다.

ProviderManager를 사용하면 인증을 수행할 수 있는 AuthenticationProvider가 없는 경우에 참조되는 선택적 상위 AuthenticationManager를 구성할 수도 있습니다. 부모는 모든 유형의 AuthenticationManager일 수 있지만 종종 ProviderManager의 인스턴스입니다.

providermanager-parent

실제로 여러 ProviderManager 인스턴스가 동일한 부모 AuthenticationManager를 공유할 수 있습니다. 이는 공통된 일부 인증(공유된 부모 AuthenticationManager)이 있지만 다른 인증 메커니즘(다른 ProviderManager 인스턴스)을 갖는 여러 SecurityFilterChain 인스턴스가 있는 시나리오에서 다소 일반적입니다.

providermanagers-parent

기본적으로 ProviderManager는 성공적인 인증 요청에 의해 반환된 인증 개체에서 중요한 자격 증명 정보를 지우려고 시도합니다. 이렇게 하면 비밀번호와 같은 정보가 HttpSession에서 필요 이상으로 오래 보관되는 것을 방지할 수 있습니다.

이는 예를 들어 상태 비저장 애플리케이션의 성능을 향상시키기 위해 사용자 개체 캐시를 사용할 때 문제를 일으킬 수 있습니다. 인증에 캐시의 개체(예: UserDetails 인스턴스)에 대한 참조가 포함되어 있고 해당 자격 증명이 제거된 경우 더 이상 캐시된 값에 대해 인증할 수 없습니다. 캐시를 사용하는 경우 이 점을 고려해야 합니다. 확실한 해결책은 먼저 캐시 구현이나 반환된 인증 개체를 생성하는 AuthenticationProvider에서 개체의 복사본을 만드는 것입니다. 또는 ProviderManager에서 erasureCredentialsAfterAuthentication 속성을 비활성화할 수 있습니다. ProviderManager 클래스에 대해서는 Javadoc을 참조하세요.

AuthenticationProvider

여러 AuthenticationProviders 인스턴스를 ProviderManager에 삽입할 수 있습니다. 각 AuthenticationProvider는 특정 유형의 인증을 수행합니다. 예를 들어 DaoAuthenticationProvider는 사용자 이름을 지원합니다.

Request Credentials with AuthenticationEntryPoint

AuthenticationEntryPoint는 클라이언트로부터 자격 증명을 요청하는 HTTP 응답을 보내는 데 사용됩니다.

때때로 클라이언트는 리소스를 요청하기 위해 자격 증명(예: 사용자 이름 및 비밀번호)을 사전에 포함합니다. 이러한 경우 Spring Security는 클라이언트로부터 자격 증명을 요청하는 HTTP 응답을 제공할 필요가 없습니다. 자격 증명이 이미 포함되어 있기 때문입니다.

다른 경우에는 클라이언트가 액세스 권한이 없는 리소스에 인증되지 않은 요청을 하는 경우도 있습니다. 이 경우 클라이언트로부터 자격 증명을 요청하는 데 AuthenticationEntryPoint 구현이 사용됩니다. AuthenticationEntryPoint 구현은 로그인 페이지로 리디렉션을 수행하거나, WWW-Authenticate 헤더로 응답하거나, 다른 작업을 수행할 수 있습니다.

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter는 사용자 자격 증명을 인증하기 위한 기본 필터로 사용됩니다. 자격 증명을 인증하기 전에 Spring Security는 일반적으로 AuthenticationEntryPoint를 사용하여 자격 증명을 요청합니다.

AbstractAuthenticationProcessingFilter는 제출된 모든 인증 요청을 인증할 수 있습니다.

abstractauthenticationprocessingfilter

  1. 사용자가 자신의 자격 증명을 제출하면, AbstractAuthenticationProcessingFilter는 HttpServletRequest에서 인증될 Authentication 객체를 생성합니다. 생성된 Authentication의 유형은 AbstractAuthenticationProcessingFilter의 서브클래스에 따라 다릅니다. 예를 들어, UsernamePasswordAuthenticationFilter는 HttpServletRequest에 제출된 사용자 이름과 비밀번호로부터 UsernamePasswordAuthenticationToken을 생성합니다.
  2. 다음으로, Authentication 객체가 AuthenticationManager에 전달되어 인증됩니다.
  3. 인증 실패 시:
    1. SecurityContextHolder가 비워집니다.
    1. RememberMeServices.loginFail이 호출됩니다. 리멤버 미(remember me)가 구성되지 않은 경우, 이는 작업 없음입니다. rememberme 패키지를 참조하세요.
    1. AuthenticationFailureHandler가 호출됩니다. AuthenticationFailureHandler 인터페이스를 참조하세요.
  1. 인증 성공 시:
    1. SessionAuthenticationStrategy가 새로운 로그인에 대해 알림을 받습니다. SessionAuthenticationStrategy 인터페이스를 참조하세요.
    1. Authentication이 SecurityContextHolder에 설정됩니다. 나중에 SecurityContext를 저장하여 향후 요청에 자동으로 설정될 수 있도록 하려면, SecurityContextRepository#saveContext가 명시적으로 호출되어야 합니다. SecurityContextHolderFilter 클래스를 참조하세요.
    1. RememberMeServices.loginSuccess가 호출됩니다. 리멤버 미가 구성되지 않은 경우, 이는 작업 없음입니다. rememberme 패키지를 참조하세요.
    1. ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent를 발행합니다.
    1. AuthenticationSuccessHandler가 호출됩니다. AuthenticationSuccessHandler 인터페이스를 참조하세요.