2022. 8. 16. 09:30ㆍ개발/Spring
아래 사이트를 번역함. 오역다수
Servlet Authentication Architecture :: Spring Security
ProviderManager is the most commonly used implementation of AuthenticationManager. ProviderManager delegates to a List of AuthenticationProviders. Each AuthenticationProvider has an opportunity to indicate that authentication should be successful, fail, or
docs.spring.io
SecurityContextHolder
SecurityContextHolder 는 Spring Security의 인증(Authentication)의 핵심 모델이다. SecurityContextHolder 는 SecurityContext 를 포함하고 있다.

Spring Security는 SecurityContextHolder 에 인증된 사용자 정보를 저장한다. 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)로 직접 세팅하게 되면 쓰레드간 경쟁상태(Race Condition)이 발생할 수 있기때문에 위 코드처럼 작성해야한다. - 인증을 위한 객체를 하나 만들었다.
SecurityContext에는 Authentication 인터페이스의 구현체를 셋팅할 수 있다. 여기선 테스트를 위해 간단한 방법의TestingAuthenticationToken를 사용했다. 일반적으론UsernamePasswordAuthenticationToken(userDetails, password, authorities)이 많이 사용된다. SecurityContextHolder에SecurityContext를 세팅한다. Spring Secuirty는 이 정보를 통해서 인가(Authorization)작업을 수행할 수 있다.
인증된 정보에서 데이터를 얻어오기 위해 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을 사용하기 때문에 항상 하나의 Thread에서만 동작함을 보장할 수 있다. 따라서 꼭 메소드를 통해서 인증 정보를 파라미터로 던지지 않아도 된다!!! ( 위 코드에서도 getContext를 사용하기만 하면 현재 Thread에서 인증된 사용자 정보만 가져올 수 있다. )
SecurityContext
SecurityContext 는 SecurityContextHolder 에 의해 관리되며 SecurityContext 는 Authentication 객체를 관리한다.
Authentication
Spring Security의 Authentication 은 2가지 목적을 가지고 있다.
AuthenticationManager에Authentication를 넣음으로써 사용자에 대한 인증정보를 제공한다.- 현재 인증된 사용자에 대한 정보를 제공한다. 현재 인증된
Authentication은SecurityContext에 포함되어 있다.
Authentication 은 아래의 3가지 내용을 포함하고 있다.
Principal- 사용자를 식별한다.credentials- 일반적으로 패스워드를 의미한다. 사용자 인증을 완료하면 유출방지를 위해 제거한다.authorities- 사용자의 Role이나 Scope를 설정할 때 사용한다.GrantedAuthority객체를 통해서 사용자의 권한을 관리할 수 있다.
GrantedAuthority
GrantedAuthority 는 사용자에게 부여된 상위 수준 권한이다. (인증된 사용자들 중에서 Role이나 Scope를 설정해야할 때 사용한다.)
GrantedAuthority는 Authentication.getAuthorities() 메소드를 통해서 얻을 수 있다. 이 메소드는 GrantedAuthority 오브젝트를 컬렉션 타입으로 제공한다. GrantedAuthority 는 흔히 권한을 뜻하게되며 일반적으로 “역할(role)”을 의미한다. 예를들면 ROLE_ADMIN ROLE_HR_SUPRVISOR 와 같은 식이다. 역할들은 이후에 배울 인가(Authorization)에서 자세히 다룬다. Spring Security의 다른 부분들은 이런 Authorities 들을 해석할 수 있으며, 반드시 존재할것으로 생각하고 동작한다. username/password 방식의 인증 방식을 사용하게될 경우 GrantedAuthority 는 UserDetailsService 를 통해 얻을 수 있다.
GrantedAuthority 는 일반적으로 애플리케이션에 광범위하게 적용된다. (덕분에 특정 도메인별로 권한을 부여하지 않아도 되며 메모리 누수를 막을 수 있다.)
AuthenticationManager
AuthenticationManager 는 Spring Security가 어떻게 인증 Filter를 관리할지 정의하는 API이다. 반환된 Authentication은 AuthenticationManager가 실행한 컨트롤러(예. Spring Security의 Filter)에 의해 SecurityContextHolder에 세팅된다. Spring Security의 Filter를 도입하지 않았다면 직접 SecurityContextHolder 에 인증정보를 세팅할 수 있으며, 이 경우엔 AuthenticationManager 가 필요없다.
AuthenticationManager 인터페이스의 구현체 중 일반적인 구현체는 ProviderManager 이다.
ProviderManager
AuthenticationManager 인터페이스의 구현체 중 가장 일반적으로 사용되는 구현체는 ProviderManager 이다. ProviderManager 는 AuthenticationProvider 목록을 관리한다.
각 AuthenticationProvider는 인증작업이 성공인지, 실패인지, 판단불가인지 판단할 수 있다. 만약 결정을 내릴 수 없다면 다른 AuthenticationProvider로 작업을 넘긴다. 만약 어떤 AuthenticationProvider도 인증을 수행하지 못한다면 ProviderNotFoundException이 발생한다.
ProviderNotFoundException은 AuthenticationException를 확장한다.

각 AuthenticationProvider를 통해 특화된 인증들을 처리할 수 있게된다. 예를들어 0번째 AuthenticationProvider에선 username/password 기반의 인증을 처리하고 1번째 AuthenticationProvider에선 SAML방식의 인증을 수행할수 있다. 따라서 AuthenticationManager 를 사용하면 다양한 인증을 하나의 Bean에서 관리할 수 있게된다.
AuthenticationProvider
AuthenticationProvider는 List형태로 ProviderManager에 의해 관리된다. 각 AuthenticationProvider는 서로 다른 인증 방법을 제공한다. 예를 들어 DaoAuthenticationProvider는 username/password 기반의 인증을 지원한다. 반면에 JwtAuthenticationProvider는 JWT token 방식의 인증을 지원한다.
Request Credentials with AuthenticationEntryPoint
AuthenticationEntryPoint는 사용자가 보낸 credential(주로 비밀번호) 정보에 대한 응답을 보낼때 사용한다.
사용자는 username/password 같은 방법을 통해 credential 정보를 포함해서 포함해서 Request를 보내기도 한다. 이런 경우에는 이미 Request에 credential 정보가 포함되어 있기때문에 Spring Security는 추가적인 credential를 요청하는 HTTP Response를 수행할 필요가 없다.
다른 경우, 사용자가 인증되지 않은채 Request를 수행할 수 있다. 이땐 AuthenticationEntryPoint의 구현체가 사용자에게 credential 정보를 요청하게 된다. AuthenticationEntryPoint 구현체는 주로 log in 페이지로 리다이렉트하거나 응답 헤더에 WWW-Authenticate를 담아 반환 할것이다.
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter는 기본적으로 Filter로 동작하며, 사용자의 credential 정보를 인증하는데 역할을 한다. credential 정보가 인증되기 전에 Spring Security는 먼저 AuthenticationEntryPoint를 통해 credential 정보를 가져온다.
그다음, AbstractAuthenticationProcessingFilter는 인증 요청에 대한 확인작업을 수행한다.

- 사용자로부터 credential 정보가 들어왔을때,
AbstractAuthenticationProcessingFilter는 인증이 필요한 HttpServletRequest로부터 Authentication 객체를 만든다.Authentication의 타입은AbstractAuthenticationProcessingFilter의 서브클래스에 따라 결정된다. 예를들어UsernamePasswordAuthenticationFilter서브클래스를 사용한다면Authentication타입으로 UserPasswordAuthenticationToken을 만들것이다. - 그다음
Authentication은AuthenticationManager로 전달된다. - 만약 인증에 실패한다면
SecurityContextHolder는 Clear된다.RememberMeService의loginFail메소드가 실행된다. 만약 remember-me 기능이 설정되어 있지 않다면 실행되지 않는다.AuthenticationFailureHandler가 실행된다.
- 만약 인증에 성공하게 된다면
SessionAuthenticationStrategy가 새로운 로그인을 인식한다.SecurityContextHolder에Authentication정보가 세팅된다. 그다음SecurityContextPersistenceFilter가SecurityContext정보를HttpSession에 저장한다.RememberMeServices의loginSuccess메소드가 실행된다. 만약 remeber-me 기능이 설정되어 있지 않다면 실행되지 않는다.ApplicationEventPublisher가InteractiveAuthenticationSuccessEvent를 발생시킨다.AuthenticationSuccessHandler가 실행된다.
'개발 > Spring' 카테고리의 다른 글
| [Spring Security] Architecture (0) | 2022.08.15 |
|---|---|
| [Resilience4j] Circuit Breaker With Spring Boot 2 (0) | 2022.07.10 |
| [Spring MVC] 구조와 환경셋팅 ( Spring Boot의 편리함. ) (0) | 2021.06.09 |