| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
- priorityqueue
- Spring
- 퀵정렬
- 트리
- BOJ
- 투포인터
- 티스토리챌린지
- 취준
- 도커교과서
- 구현
- Queue
- DP
- N과M
- BFS
- 백트래킹
- programmers
- JPA
- Java
- docker
- 코딩테스트
- 이분탐색
- Stack
- 오블완
- Simulation
- dfs
- 이진탐색
- 그리디
- MySQL
- Security
- CS
- Today
- Total
Untitled1.class
Spring Security Authentication Architecture 본문
Servlet Authentication Architecture
- SecurityContextHolder: Spring Security가 인증 대상자의 세부 정보를 저장하는 곳
- SecurityContext: SecurityContextHolder에서 가져오며, 현재 인증된 사용자의 Authentication을 포함
- Authentication: 사용자가 인증하기 위해 제공한 자격 증명 또는 SecurityContext의 현재 사용자를 제공하기 위해 AuthenticationManager에 입력될 수 있음
- GrantedAuthority: 인증에 대한 주체에게 부여된 권한(예: 역할, 범위 등)
- AuthenticationManager: Spring Security Filter가 인증을 수행하는 방식을 정의하는 API
- ProviderManager: 가장 일반적인 AuthenticationManager 구현
- AuthenticationEntryPoint를 사용한 자격 증명 요청: Client에게 자격 증명을 요청하는 데 사용됨(예: login page로 redirection, WWW-Authenticate 응답 전송 등)
- AbstractAuthenticationProcessingFilter: 인증에 사용되는 기본 Filter. 이는 또한 인증의 높은 수준의 흐름과 각 부분이 어떻게 함께 작동하는지에 대한 좋은 아이디어를 제공
SecurityContextHolder
Spring Security 인증 모델의 핵심은 SecurityContextHolder이다.
SecurityContextHolder는 SecurityContext를 포함한다.

SecurityContextHolder는 Spring Security가 인증된 사용자에 대한 세부 정보를 저장하는 곳이다. Spring Security는 SecurityContextHolder가 어떻게 채워지는지는 신경 쓰지 않는다. 값이 포함되어 있으면 현재 인증된 사용자로 사용된다.
사용자가 인증되었음을 나타내는 가장 간단한 방법은 SecurityContextHolder를 직접 설정하는 것이다.
SecurityContext context = SecurityContextHolder.createEmptyContext(); // 1
Authentication authentication =
new TestingAuthenticationToken("username", "password", "ROLE_USER"); // 2
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context); // 3
- 먼저 빈 SecurityContext를 생성한다. 여러 스레드에서 경합 조건을 방지하려면 SecurityContextHolder.getContext().setAuthentication(authentication) 대신 새 SecurityContext instance를 생성해야 한다.
- 다음으로, 새 Authentication 객체를 생성한다. Spring Security는 SecurityContext에 설정된 Authentication 구현 유형을 고려하지 않는다. 여기서는 매우 간단한 TestingAuthenticationToken을 사용한다. 더 일반적인 프로덕션 시나리오는 UsernamePasswordAuthenticationToken(userDetails, password, authority)이다.
- 마지막으로, SecurityContextHolder에 SecurityContext를 설정한다. Spring Security는 이 정보를 사용하여 권한을 부여한다.
인증된 주체에 대한 정보를 얻으려면 SecurityContextHolder에 액세스하라.
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가 해당 method에 인수로 명시적으로 전달되지 않더라도 동일한 스레드의 method에서 SecurityContext를 항상 사용할 수 있다. 현재 주체의 요청이 처리된 후 스레드를 삭제하는 경우 이러한 방식으로 ThreadLocal을 사용하는 것이 매우 안전하다. Spring Security의 FilterChainProxy는 SecurityContext가 항상 삭제되도록 보장한다.
일부 Application은 스레드를 사용하는 특정 방식 때문에 ThreadLocal을 사용하기에 적합하지 않을 수 있다. 예를 들어, Swing Client는 Java Virtual Machine의 모든 스레드가 동일한 보안 컨텍스트를 사용하기를 원할 수 있다. 시작 시 SecurityContextHolder 전략을 설정하여 컨텍스트를 저장할 방식을 지정할 수 있다.
독립 실행형 Application의 경우 SecurityContextHolder.MODE_GLOBAL 전략을 사용한다. 다른 Application은 보안 스레드에서 생성된 스레드도 동일한 보안 ID를 갖기를 원할 수 있다. SecurityContextHolder.MODE_INHERITABLETHREADLOCAL을 사용하면 이를 구현할 수 있다.
두 가지 방법으로 기본 SecurityContextHolder.MODE_THREADLOCAL 모드를 변경할 수 있다. 첫 번째는 시스템 속성을 설정하는 것이다. 두 번째는 SecurityContextHolder의 정적 메서드를 호출하는 것이다. 대부분의 Application은 기본 모드를 변경할 필요가 없다. 하지만 변경해야 하는 경우, SecurityContextHolder에 대한 JavaDoc을 참조하라.
SecurityContext
SecurityContext는 SecurityContextHolder에서 가져온다. SecurityContext에는 Authentication 객체가 포함되어 있다.
Authentication
Authentication interface는 Spring Security에서 두 가지 주요 목적을 수행한다.
- AuthenticationManager에 사용자가 인증하기 위해 제공한 자격 증명을 입력으로 제공한다. 이 시나리오에서 isAuthenticated()를 사용하면 false가 반환된다.
- 현재 인증된 사용자를 나타낸다. SecurityContext에서 현재 인증을 가져올 수 있다.
Authentication에는 다음이 포함된다:
- principal: 사용자를 식별한다. 사용자 이름/비밀번호로 인증하는 경우 UserDetails의 instance인 경우가 많다.
- credentials: 비밀번호이다. 많은 경우, 사용자 인증 후 유출 방지를 위해 삭제된다.
- authorities: GrantedAuthority instance는 사용자에게 부여된 상위 수준 권한이다. 역할과 범위가 그 예이다.
GrantedAuthority
GrantedAuthority instance는 사용자에게 부여되는 상위 수준 권한이다. 역할과 범위가 그 예이다.
Authentication.getAuthorities() method에서 GrantedAuthority instance를 가져올 수 있다. 이 method는 GrantedAuthority 객체의 컬렉션을 제공한다. GrantedAuthority는 당연히 보안 주체에게 부여되는 권한이다. 이러한 권한은 일반적으로 ROLE_ADMINISTRATOR 또는 ROLE_HR_SUPERVISOR와 같은 “역할”이다. 이러한 역할은 나중에 웹 권한 부여, method 권한 부여 및 도메인 객체 권한 부여를 위해 구성된다. Spring Security의 다른 부분은 이러한 권한을 해석하고 해당 권한이 존재할 것으로 예상한다. 사용자 이름/비밀번호 기반 인증을 사용하는 경우 GrantedAuthority instance는 일반적으로 UserDetailsService에 의해 로드된다.
일반적으로 GrantedAuthority 객체는 Application 전체 권한이며, 특정 도메인 객체에 국한되지 않는다. 따라서 Employee 객체 번호 54에 대한 권한을 나타내는 GrantedAuthority를 사용하지 않을 가능성이 높다. 그러한 권한이 수천 개라면 메모리가 빠르게 고갈되거나 적어도 Application이 사용자를 인증하는 데 오랜 시간이 걸리기 때문이다. 물론 Spring Security는 이러한 일반적인 요구사항을 처리하도록 설계되었지만, 대신 프로젝트의 도메인 객체 보안 기능을 사용해야 한다.
AuthenticationManager
AuthenticationManager는 Spring Security의 Filter가 인증을 수행하는 방식을 정의하는 API이다. 반환된 Authentication은 AuthenticationManager를 호출한 Controller(즉, Spring Security의 Filter instance)에 의해 SecurityContextHolder에 설정된다. Spring Security의 Filter instance와 통합하지 않는 경우, SecurityContextHolder를 직접 설정할 수 있으며 AuthenticationManager를 사용할 필요가 없다.
AuthenticationManager는 어떤 방식으로든 구현할 수 있지만, 가장 일반적인 구현은 ProviderManager이다.
ProviderManager
ProviderManager는 가장 일반적으로 사용되는 AuthenticationManager 구현이다. ProviderManager는 AuthenticationProvider instance 목록에 위임한다. 각 AuthenticationProvider는 인증이 성공해야 하는지, 실패해야 하는지, 또는 스스로 결정을 내릴 수 없고 하위 AuthenticationProvider가 결정을 내릴 수 있는지를 나타낼 수 있다. 구성된 AuthenticationProvider instance 중 어느 것도 인증할 수 없는 경우, ProviderNotFoundException이 발생하며 인증이 실패한다. ProviderNotFoundException은 ProviderManager가 전달된 인증 유형을 지원하도록 구성되지 않았음을 나타내는 특수한 AuthenticationException이다.

실제로 각 AuthenticationProvider는 특정 유형의 인증을 수행하는 방법을 알고 있다. 예를 들어, 한 AuthenticationProvider는 사용자 이름/비밀번호의 유효성을 검사할 수 있고, 다른 AuthenticationProvider는 SAML assertion을 인증할 수 있다. 이를 통해 각 AuthenticationProvider는 여러 유형의 인증을 지원하면서 매우 구체적인 유형의 인증을 수행하고 단일 AuthenticationManager bean만 노출할 수 있다.
ProviderManager는 또한 인증을 수행할 수 있는 AuthenticationProvider가 없는 경우 참조되는 선택적 부모 AuthenticationManager를 구성할 수 있다. 부모는 모든 유형의 AuthenticationManager가 될 수 있지만, 일반적으로 ProviderManager의 instance이다.

실제로 여러 ProviderManager instance가 동일한 부모 AuthenticationManager를 공유할 수 있다. 이는 공통된 인증(공유 부모 AuthenticationManager)을 갖는 여러 SecurityFilterChain instance가 있지만, 서로 다른 인증 메커니즘(서로 다른 ProviderManager instance)을 갖는 상황에서 다소 일반적이다.

기본적으로 ProviderManager는 인증 요청이 성공하면 반환되는 Authentication 객체에서 민감한 자격 증명 정보를 지우려고 시도한다.(CredentialsContainer interface) 이를 통해 비밀번호와 같은 정보가 HttpSession에 필요 이상으로 오래 보관되는 것을 방지할 수 있다.
예를 들어, 상태 비저장 애플리케이션의 성능을 향상시키기 위해 사용자 객체 캐시를 사용할 때 문제가 발생할 수 있다. Authentication에 캐시에 있는 객체(예: UserDetails instance)에 대한 참조가 포함되어 있고 해당 객체의 자격 증명이 제거된 경우, 캐시된 값으로 더 이상 인증할 수 없다. 캐시를 사용하는 경우 이 점을 고려해야 한다. 확실한 해결책은 캐시 구현이나 반환된 Authentication 객체를 생성하는 AuthenticationProvider에서 먼저 객체의 복사본을 만드는 것이다. 또는 ProviderManager의 eraseCredentialsAfterAuthentication 속성을 비활성화할 수 있다. ProviderManager class에 대한 Javadoc을 참조하라.
AuthenticationProvider
ProviderManager에 여러 개의 AuthenticationProvider instance를 주입할 수 있다. 각 AuthenticationProvider는 특정 유형의 인증을 수행한다. 예를 들어 DaoAuthenticationProvider는 사용자 이름/비밀번호 기반 인증을 지원하고 JwtAuthenticationProvider는 JWT 토큰 인증을 지원한다.
Request Credentials with AuthenticationEntryPoint
AuthenticationEntryPoint는 Client에게 자격 증명을 요청하는 HTTP 응답을 전송하는 데 사용된다.
Client가 리소스를 요청하기 위해 사용자 이름 및 비밀번호와 같은 자격 증명을 사전에 포함하는 경우가 있다. 이러한 경우, Spring Security는 자격 증명이 이미 포함되어 있으므로 Client에게 자격 증명을 요청하는 HTTP 응답을 제공할 필요가 없다.
다른 경우에는 Client가 액세스 권한이 없는 리소스에 대해 인증되지 않은 요청을 수행한다. 이 경우, AuthenticationEntryPoint 구현체를 사용하여 Client에게 자격 증명을 요청한다. AuthenticationEntryPoint 구현체는 login page로 redirection하거나, WWW-Authenticate Header로 응답하거나, 다른 작업을 수행할 수 있다.
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter는 사용자 자격 증명을 인증하는 기본 Filter로 사용된다. 자격 증명을 인증하기 전에 Spring Security는 일반적으로 AuthenticationEntryPoint를 사용하여 자격 증명을 요청한다.
그런 다음 AbstractAuthenticationProcessingFilter는 자신에게 제출된 모든 인증 요청을 인증할 수 있다.

- 사용자가 자격 증명을 제출하면 AbstractAuthenticationProcessingFilter는 HttpServletRequest에서 인증을 위한 Authentication을 생성한다. 생성되는 Authentication 유형은 AbstractAuthenticationProcessingFilter의 하위 class에 따라 달라진다. 예를 들어, UsernamePasswordAuthenticationFilter는 HttpServletRequest에서 제출된 사용자 이름과 비밀번호에서 UsernamePasswordAuthenticationToken을 생성한다.
- 다음으로, Authentication은 인증을 위해 AuthenticationManager로 전달된다.
- 인증이 실패하면 Failure가 발생한다.
- SecurityContextHolder가 삭제된다.
- RememberMeServices.loginFail이 호출된다. RememberMe가 구성되지 않은 경우 아무런 작업도 수행되지 않는다. RememberMe 패키지를 참조하라.
- AuthenticationFailureHandler가 호출된다. AuthenticationFailureHandler interface를 참조하라.
- 인증이 성공하면 Success가 발생한다.
- SessionAuthenticationStrategy에 새 login 알림이 전송된다. SessionAuthenticationStrategy interface를 참조하라.
- 인증은 SecurityContextHolder에 설정된다. 나중에 SecurityContext를 저장하여 향후 요청 시 자동으로 설정되도록 하려면 SecurityContextRepository#saveContext를 명시적으로 호출해야 한다.
- RememberMeServices.loginSuccess가 호출된다. RememberMe가 구성되어 있지 않으면 아무런 작업도 수행되지 않는다.
- ApplicationEventPublisher는 InteractiveAuthenticationSuccessEvent를 발행한다.
- AuthenticationSuccessHandler가 호출된다.
참조 - https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html
'공부 > Spring Security' 카테고리의 다른 글
| Method Security (0) | 2025.05.13 |
|---|---|
| Authorize HttpServletRequests (0) | 2025.05.13 |
| Username/Password Authentication (0) | 2025.05.13 |
| Spring Security Authorization Architecture (0) | 2025.05.13 |
| Spring Security Servlet Applications Architecture (0) | 2025.05.12 |
