고인물을 지양하는 블로그

[Spring Security] Spring Security 아키텍처 & Authentication 본문

카테고리 없음

[Spring Security] Spring Security 아키텍처 & Authentication

yunjaeGong 2021. 10. 20. 12:16

1. Spring FilterChain

클라이언트로부터 요청(HttpServletRequest)이 들어오면, 요청이 Spring MVC에서 처리되기 전에 우선 Spring Security FilterChain을 거치게 된다. 

도큐먼트를 보면(출처)

필터 체인이란, 필터, 서블릿들의 조합을 말한다.
하나의 Http 요청에 대한 계층화된 핸들러의 모임이다.
요청이 여러 필터들을 통과하며 필터는 하위 필터로 전달을 막을 수도, 하위 필터/서블릿에서 사용될 수 있도록 request 요청을 수정할 수도 있다. 

 

도큐먼트 설명만 봐서는 잘 와닿지 않는데, 실제 프로젝트에서 사용되는 사용례는 다음과 같을 것이다.

  • 설정을 기준으로, 요청한 URL에 공개적으로 액세스 할 수 있는지 확인.
  • 세션 기반 인증 확인의 경우 사용자가 현재 세션에서 이미 인증되었는지 확인.
  • 사용자에게 요청된 작업을 수행할 수 있는 권한이 있는지 등을 확인.
  • JWT Authorization Token, Refresh Token 발급

Spring Security가 제공하는 기본 FilterChain을 이용하거나/ 사용자가 필요한 기능을 필터로 추가해서 FilterChain을 이용할 수 있다. 다만 필터 체인에서 필터들이 수행되는 순서가 있으므로, 내가 만든 기능이 상위 필터에서 이미 처리될 수 있으니 커스텀 필터를 추가할 때는 삽입하는 필터의 순서가 중요하다.

 

2. Authentication

html form에서 form에 입력한 username, password를 Post 요청해 form login을 요청할 때

Spring Security 내부에서는 username, password를 UsernamePasswordAuthenticationFilter가 캐치해 UsernamePasswordAuthenticationToken을 발급한다.

 

이렇게 되면 위 그림의 2번을 지나는 상태가 된다.

 

그다음, 이 토큰은 AuthenticationManager에 전달되고 AuthenticationManager는 이 토큰 인증을 시도한다.

성공하면 Authentication 정보가 SecurityContextHolder에 저장된다.

 

SecurityContextHolder에 로그인 정보가 정상적으로 등록되면 SecurityContextHolder에서 Principal (인증된 사용자 정보)에 접근해 다른 용도로 사용할 수 있다.

 

-> 일단 SecurityContextHolder에 들어있는 Authentication 정보는 어떤 방법을 (위와 같은 AuthenticationManager를 통한 방법 혹은 직접 SecurityContextHolder에 주입) 이용하였건 간에 그 존재 자체가 인증 완료의 의미를 가진다.

 

3. SecurityContextHolder

 

SecurityContextHolder는 인증이 완료된 사용자들의 정보를 저장하는 곳이다. SecurityContextHolder에 어떤 방법으로 Authentication이 등록되었나는 중요하지 않고, 현재 Authentication이 저장되어 있는지, 존재한다면 그 사용자라는 인증된 사용자임이 중요하다.

 

SecurityContextHolder 안에 들어가는 Authentication 객체는 Principal, Credentials, Authorization으로 구성된다.

 

  • Principal - 사용자를 식별하는 객체로, username/password 인증 구성에서는 주로 UserDetailsService이다.
  • Credential - 암호일 수도 있습니다. 대부분의 경우 유출되지 않도록 사용자가 인증되면 지워진다.
  • Authorization - 부여된 역할, 스코프를 기준으로 하는 High Level 권한(GrantedAuthority)이다. e.g. ROLE_USER, ROLE_ADMIN

Username, Password를 이용한 로그인을 기준으로, 개괄적인 Spring Security 동작은 위와 같다.

 

3. AuthenticationManager & AuthenticationProvider(s)

AuthenticationManager는 Spring Security의 필터가 인증을 수행하는 방법을 정의하는 API이다.

그다음, 반환되는 Authentication은 AuthenticationManager를 호출한 컨트롤러(Spring Security 필터)에 의해 SecurityContextHolder에 설정된다. 

 

 

Authentication Manager는 인증 수행 방법을 정의한 인터페이스이기 때문에, 실제 구현으로는 주로 ProviderManager를 사용한다. 

 

ProviderManager는 FilterChain과 비슷한 구조로 이루어진 AuthenticationProvider들에게 인증을 요청을 위임(요청)하고, 

AuthenticationProvider 로 전달된 인증 요청이 특정 인증 유형을 지원하도록 구성되지 않았으면 ProviderNotFound Exception 발생하고, 그 이외에는 적절한 AuthenticationProvider에 의해 인증 된다.

 

내부 동작은 조금 복잡해 보이지만, 프로그래밍 과정에서 인증 과정은 다음과 같다.

// authentication token 생성
UsernamePasswordAuthenticationToken token =
   new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());

// PrincipalDetailsService의 loadUserByUsername가 실행된 후 정상이 authentication이 반환됨
Authentication authentication = authenticationManager.authenticate(token);

1. UsernamePasswordAuthenticationToken 발급

2. AuthenticationManager에 인증 요청

  - 해당 요청에 대한 인증을 처리할수 있는 Provider를 찾고, 해당 인증 유형에 따라 처리한 뒤 인증정보가 담긴 Authentication 객체를 반환

  

 

 

혹은 위에서 가장 쉬운 방법이라고 소개한 방법처럼, SecurityContextHolder에 직접 Authentication을 추가하는 방법도 있다.

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

SecurityContextHolder.setContext(context);
Comments