SecurityContextHolder
스프링 시큐리티 인증 모델의 핵심으로 SecurityContext를 포함한다.
Holder라는 단어의 의미를 생각해 보면 이해하기 쉬운데
여기서 Holder는 소유자, 보유자 같은 의미로
SecurityContext를 가지고 있는 존재라는 것이다.
위의 사진을 보면 SecurityContext는 인증과 관련된 정보들을 가지고 있는데
즉, SecurityContextHolder는 이러한 SecurityContext들을 저장하는 공간이다.
//SecurityContextHolder에 저장할 SecurityContext를 하나 생성
SecurityContext context = SecurityContextHolder.createEmptyContext();
//SecurityContext에 저장할 인증정보 생성
Authentication authentication =
new TestingAuthenticationToken("username", "password", "ROLE_USER");
//SecurityContext에 생성한 인증정보 할당
context.setAuthentication(authentication);
//SecurityContext를 SecurityContextHolder에 저장
SecurityContextHolder.setContext(context);
SecurityContextHolder에 SecurityContext를 저장하는 간단한 코드다.
결국 인증에 대한 모든 정보들은 SecurityContextHolder가 가지고 있기 때문에
이를 얻기 위해서는 SecurityContextHolder에 접근해야 한다.
//SecurityContextHolder에서 SecurityContext 가져오기
SecurityContext context = SecurityContextHolder.getContext();
//SecurityContext에서 인증정보 가져오기
Authentication authentication = context.getAuthentication();
//인증정보에서 필요한 정보들 가져오기
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
SecurityContextHolder >> SecurityContext >> Authentication
위와 같은 순서로 인증정보에 접근할 수 있다.
SecurityContextHolder는 ThreadLocal을 사용해 인증에 대한 상세정보들을 저장하는데
이해하기 쉽게 설명하자면 동일한 스레드의 메서드에서는 SecurityContext룰 언제든 사용할 수 있다.
public void testMethod(파라미터로 SecurityContextHolder를 받지 않아도) {
//아래의 과정들을 그대로 수행할 수 있음
//SecurityContextHolder에서 SecurityContext 가져오기
//SecurityContext에서 인증정보 가져오기
//인증정보에서 필요한 정보들 가져오기
}
SecurityContext를 메서드의 파라미터 같은 것으로 전달받지 않아도
현재 스레드의 어떤 메서드에서든 SecurityContextHolder를 통해
SecurityContext에 접근할 수 있다는 것이다.
SecurityContext
위에서 살펴봤던 것처럼 인증정보를 감싸고 있는 객체로
SecurityContextHolder에 포함된다.
Authentication
Authentication은 스프링 시큐리티에서 두 가지 목적을 가지고 사용할 수 있다.
첫 번째로는 인증을 위한 크레덴셜을 제공하기 위한 AuthenticationManager에 대한 입력으로
이 경우에는 isAuthenticated()의 리턴값은 false다.
두 번째로는 현재 인증된 사용자를 나타내기 위한 경우로
위에서 살펴본 SecurityContext로부터 인증정보를 얻을 때 사용된다.
정리하자면 인증을 위한 크레덴셜 제공과
이미 인증된 사용자의 정보를 얻기 위한 목적을 가지고 있다.
다음의 3가지를 포함한다.
- Principal : 보안주체로 사용자를 식별할 때 사용된다.
- Credentials : 인증에 필요한 수단으로 보통 패스워드를 의미한다.
- Authorities : GrantedAuthority 객체로 사용자가 어디까지 접근할 수 있는지에 대한 권한이다.(역할 및 범위)
GrantedAuthority
인증된 사용자가 어떤 요청까지 가능한지에 대한 권한을 부여하는 객체로
역할 기반과 범위 기반 방식이 있다.
예를 들면, 로그인한 사용자의 역할이 일반 사용자인지 관리자인지에 따라
어떤 페이지에(요청) 접근할 수 있는지 통제할 수 있다.
AuthenticationManager
스프링 시큐리티 필터가 인증을 어떻게 수행하는지 정의하는 API로
실질적인 인증을 직접 처리하는 것이 아니라
인증 과정들을 순서대로 진행하도록 조율한다.
AuthenticationManager를 통해 최종적으로 반환된 Authentication은
AuthenticationManager를 호출한 컨트롤러(사실상 스프링 시큐리티의 필터)에 의해
SecurityContext에 감싸져 SecurityContextHolder에 저장된다.
SecurityContextHolder에 대해서 살펴볼 때 봤던 코드처럼
직접 지정하거나 AuthenticationManager를 사용하지 않는 방법도 있다.
일반적으로 AuthenticationManager의 구현 클래스는 ProviderManager다.
ProviderManager
ProviderManager는 인증의 수행을 AuthenticationProvider의 인스턴스 목록에 위임하는데
각각의 AuthenticationProvider는 인증의 성공, 실패에 대해 결정하거나
결정할 수 없는 경우 다음 AuthenticationProvider가 결정할 수 있도록 한다.
즉, 각각의 AuthenticationProvider는 특정 인증 방식에 대한 인증을 수행하는데
예를 들어 첫번째 AuthenticationProvider는 Username/Password 방식을 수행하면
다른 하나는 SAML 방식의 인증을 수행한다.
간단하게 설명하자면 하나의 ProviderManager를 통해
여러 인증 방식(AuthenticationProvider)을 사용할 수 있다.
AuthenticationProvider
여러 인증 방식(AuthenticationProvider)을 ProviderManager에 주입할 수 있다.
위에서도 언급했듯이 각각의 AuthenticationProvider는 특정 인증을 수행하는데
예를 들면 DaoAuthenticationProvider를 주입하면 유저네임/패스워드 기반의 인증을,
JwtAuthenticationProvider를 주입하면 JWT 토큰 방식의 인증도 수행할 수 있다.
Request Credentials with AuthenticationEntryPoint
클라이언트에게 자격증명을 요청하는 HTTP 응답을 처리할 때 사용된다.
쉽게 말하자면 인증되지 않은 요청에 대해 클라이언트에게 다시 인증을 요구하는 것으로
로그인하지 않은 사용자가 마이 페이지에 접속하는 경우에
로그인 페이지로 리다이렉트 하는 경우에 사용된다고 이해하면 된다.
AbstractAuthenticationProcessingFilter
사용자의 크레덴셜을 인증하기 위한 기본 필터로
크레덴셜이 인증되기 전에 스프링 시큐리티는 일반적으로
AuthenticationEntryPoint를 사용해 크레덴셜을 요청한다.
그 후에 AbstractAuthenticationProcessingFilter가
제출된 모든 인증 요청에 대해 인증할 수 있다.
간단하게 순서를 살펴보자면 아래와 같다.
- 사용자가 자신의 크레덴셜을 제공
- AbstractAuthenticationProcessingFilter가 인증할 Authentication을 생성 (아직 인증되지 않은 상태)
- 생성된 Authentication이 AuthenticationManager에 전달
- 인증에 실패하면 SecurityContextHolder를 비우고 실패에 대한 작업을 진행
- 인증에 성공하면 SecurityContextHolder에 Authentication을 저장하는 등 성공에 대한 작업 진행
'Back-End > Security' 카테고리의 다른 글
[스프링 시큐리티] 공식문서로 배워보기 : Username/Password - 2 (0) | 2023.08.15 |
---|---|
[스프링 시큐리티] 공식문서로 배워보기 : Username/Password - 1 (0) | 2023.08.14 |
[스프링 시큐리티] 공식문서로 배워보기 : 의존성 추가 (0) | 2023.08.11 |
OAuth 2.0 동작 방식 (0) | 2023.07.17 |
OAuth 2.0 (0) | 2023.07.17 |