[SpringSecurity] 인증 아키텍쳐

su_y2on·2022년 7월 7일
0

Security

목록 보기
3/4
post-thumbnail

Servlet Authentication Architecture

Spring Security에서 가장 중요한 인증 아키텍쳐를 보도록 하겠습니다.



1. SecurityContextHolder

Spring Security에서 인증된 사용자의 정보를 저장하는 곳입니다.

가장 간단한 방법은 이 SecurityContextHolder에 직접 Authentication을 넣은 SecurityContext
를 넣어주는 것입니다.


// 1. SecurityContext생성
SecurityContext context = SecurityContextHolder.createEmptyContext(); 
// 2. Authentication생성 
Authentication authentication =
    new TestingAuthenticationToken("username", "password", "ROLE_USER"); 
context.setAuthentication(authentication);
// 3. SecurityContextHolder에 넣기 
SecurityContextHolder.setContext(context); 

2번에서는 어떤 Authentication구현체로 생성하든 상관없지만 UsernamePasswordAuthenticationToken(userDetails, password, authorities)이 가장 많이 쓰입니다.



이렇게 인증된 유저를 SecurityContextHolder에 넣어주었다면 인증된 사용자의 정보가 필요하면 다시 SecurityContextHolder에 접근해서 가져오면 됩니다.

// 1. SecurityContext 꺼내오기 
SecurityContext context = SecurityContextHolder.getContext();
// 2. Authentication 꺼내오기 
Authentication authentication = context.getAuthentication();
// 3. 사용자 정보 꺼내오기 
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

근데 여기서 하나 의문은 꼭 SecurityContextHolder에 하나의 Context만 있는 것처럼 작성되어있다는 것입니다. 만약 여러 인증된 사용자들이 담겨있다면 아무 구분없이 어떻게 해당 사용자가 들어있는 Context를 가져오는 것일까요?


이에 대한 답은 ThreadLocal에서 찾을 수 있습니다.
SecurityContextHolder의 기본방식이 ThreadLocal인데요. 즉 스레드마다 독립적으로 SecurityContext를 갖게됩니다. 따라서 지금과 같은 코드에서는 같은 thread에서 넣은 인증된 유저정보를 가져오게 되는 것입니다.


이런 방식은 필요에따라 system property나 static method를 통해서 바꿀 수 있습니다.
다른전략들

  • SecurityContextHolder.MODE_GLOBAL
  • SecurityContextHolder.MODE_INHERITABLETHREADLOCAL




2. SecurityContext

SecurityContextHolder를 통해서 얻을 수 있으며 Authentication객체를 담고있습니다.



3. Authenticaton

Spring Security에서 두가지 목적으로 쓰입니다

1) AuthenticationManager의 입력값

사용자가 인증받기위해 제공한 credentials를 AuthenticationManager에게 제공
-> 위와 같은 코드는 ContextHolder에 직접주입한경우 즉, isAuthentication()이 False반환


2) 최근에 인증받은 사용자 보여주기

SecurityContext에서 꺼내볼 수 있음



또한 구성요소는 세가지 입니다

1) principal

사용자를 식별합니다. username/password를 사용할 경우 UserDetails객체가 됩니다.

2) credentials

대부분 비밀번호이며 인증된 뒤에는 유출을 막기위해 지웁니다.

3) authorities

GrantedAuthority는 높은 수준의 permission이며 roles와 scopes가 있습니다.



GrantedAuthority

Authentication.getAuthorities()를 통해서 얻을 수 있으며 GrantedAuthority들의 Collections가 반환됩니다. 주로 ROLE_ADMINISTRATOR, ROLE_USerroles같은 roles를 사용합니다. 이런 roles는 후에 Authorization(인가)에 판단기준이 됩니다.




4. AuthenticationManager

Spring Security의 Filters가 authentication을 처리하는 API입니다. AuthenticationManager에서 반환된 Authentication은 SecurityContextHolder에 저장됩니다. AuthenticationManger의 도움없이 직접 ContextHolder에 Authentication을 주입할 수 있습니다.(처음 코드와 같이)




5. ProviderManager

가장 자주 사용되는 AuthenticationManager의 구현체입니다. ProviderManger는 AuthenticationProvider의 리스트에 할일들을 위임합니다.

이때 적절한 AuthenticationProvider를 찾지못하면 인증은 실패하고 ProviderNotFoundException를 발생시킵니다.



아래와 같이 둘이상의 ProviderManager가 부모를 공유할 수 있습니다. 따라서 이 자식 ProviderManger는 겹치는 부분(Parent)과 다른부분(각각)을 갖고있게 됩니다. 또 ProviderManger는 성공적인 authentication request에 대해서는 credentials(주로 비밀번호)를 지웁니다. 유출의 위험을 막기위해서죠! 물론 필요에 따라 eraseCredentialsAfterAuthentication 옵션을 disabled시킬 수도있습니다.




6. AuthenticationProvider

여러 AuthenticationProviderProviderManger에 주입될 수 있으며 각자 다르게 행동합니다. 예를들어 DaoAuthenticationProvider는 username/password를 기반으로 인증하지만 JwtAuthenticationProvider는 JWT 토큰을 기반으로 인증을 합니다.




7. AbstractAuthenticationProcessingFilter

이 Filter는 user를 인증하기 위한 기본적은 Filter입니다.

1) 먼저 사용자가 입력한 credentials를 가지고 Authentication을 생성합니다. 이는 어떤 subclass Filter냐에 따라 달라집니다. 예를 들어 UsernamePasswordAuthenticationFilter는 UsernamePasswordAuthenticationToken를 만듭니다.

2) Authentication은 AuthenticationManger를 통해 인증과정을 거칩니다.

3) 만약 인증이 실패된다면

  • SecurityContextHolder를 비웁니다
  • RememberMeService를 사용한다면 loginFail을 발생시킵니다
  • AuthenticationFailureHandler가 동작합니다

4) 인증이 성공하면

  • SessionAuthenticationStrategy가 새로운 로그인을 인식합니다.
  • Authentication을 SecurityContextHolder에 넣습니다
  • 이후에 SecurityContext를 HttpSession에 저장합니다
  • RememberMeServices를 사용한다면 loginSuccess가 발생합니다.
  • ApplicationEventPublisherInteractiveAuthenticationSuccessEvent 발생시킵니다.
  • AuthenticationSuccessHandler가 발생합니다.





출처

0개의 댓글