개발 일지

Spring Security 인증 동작 과정(1) - 인증과 인가 본문

Spring/Spring Security

Spring Security 인증 동작 과정(1) - 인증과 인가

junjun_ 2023. 1. 31. 16:24

Spring Security란?

스프링 시큐리티 (Spring Security)는 스프링 기반 애플리케이션의 보안(인증과 인가)을 담당하는 스프링 하위 프레임워크이며 Filter 기반으로 동작한다.
보안과 관련해서 체계적으로 많은 옵션들을 제공해 주기 때문에 개발자의 입장에서는 하나하나 보안 관련 로직을 작성하지 않아도 된다는 장점이 있다.

 

이번 포스트에서는 먼저 인증과 인가가 무엇인지와 전체적인 인증 동작 과정에 대하여 정리하고 다음포스트에서 Filter에서 어떤 동작이 이루어지는지 코드를 통해 자세히 정리해 보도록 하겠습니다.

 

 


인증과 인가

인증(Authentication) 

  • 인증이란 식별 가능한 정보 (이름 , 이메일)를 이용하여 유저의 신원 입증하는 과정이다.
  • 로그인하는 과정 자체

인가(Authorize)

  • 인증된 사용자 권한을 확인하는 절차
  • 권한: 보호된 리소스에 접근 가능한지를 결정하는 것을 의미

 

Spring Security 인증 동작 과정

가장 기본적인 Form Login에 대한 흐름을 살펴보겠습니다. 

 

Spring security는 AuthenticationManager가 가지고 있는 provider 목록을 순회하면서 provider가 실행 가능한 경우에 provider의 authenticate 메소드를 호출하여 인증 절차를 수행한다.

 

1. Http Request

  • 위에서 Spring Security는 필터를 기반으로 동작하고. 이 필터들을 필터 체인이라고 한다.
  • 요청(request)은 해당 요청과 관련된 인증 필터를 찾을 때까지 필터체인을  통과한다.
  • Form로그인 요청은 UsernamePasswordAuthenticationFilter에 걸리게 된다. 

 

 2, 3.  [AuthenticationFilter] 인증객체를 생성하고  AuthenticationManager에게 인증처리 위임

  • 요청(request)이 관련 AuthenticationFilter에(UsernamePasswordAuthenticationFilter) 의해 수신되면
  • 입력된 사용자 username과 password를 추출하여 인증객체(Authentication)를 만든다.
    • From Login의 경우 Authentication의 구현체 UsernamePasswordAuthenticationToken이 만들어진다.
  • 정상적으로 생성이 완료되면 AuthenticationFilter는 AuthenticationManager에게 인증객체를 넘기며 인증처리를 위임한다.

 

4. [AuthenticationManager] 적절한 AuthenticationProvider에게 인증처리를 위임

  • AuthenticationManager를 구현한 ProviderManager은 List형태로 AuthenticationProvider들을 갖고 있다
  • 가지고 있는 provider들을 탐색하면서 각 provider들의 supports메서드를 통해 처리할 수 있는 provider를 찾는다. 
    • UsernamePasswordAuthenticationToken을 검증할 수 있는 provider은 DaoAuthenticationProvider이다
  • 해당 AuthenticationProvider에게 실제 인증처리를 위임한다

 

5. [AuthenticationProvider] UserDetailsService의 loadUserByUsername메서드 수행

  • AuthenticationProvider는 UserDetailsService의 loadUserByUsername메서드를 호출한다.
  • 이때 username 정보를 인자로 보낸다.

 

6. [UserDetailsService] 해당 username을 회원정보를 UserDetails 타입으로 반환

  • UserDetailsService의 loadUserByUsername메서드는 전달받은 username으로 DB에 저장된 회원 정보를 조회하여
  • usermamer과 일치하는 정보가 있다면  UserDetails 인터페이스를 구현한 객체를 반환하고
  • 없으면 예외를 발생시킨다.

 

7, 8, 9. [AuthenticationProvider] 검증이 성공적이었다면, Authentication 객체를 새로 생성해 반환

  • Provider에서는 passwordEncoder을 사용해서 UserDetailsService에서 받아온 UserDetails과
  • 2번에서 사용자의 입력기반으로 만든 인증객체의 password 정보를 비교하여 검증이 성공적이었다면,
  • 검증여부가 성공으로 체크된 Authentication 객체를 새로 생성해 반환해 줍니다.

 

10. [AuthenticationFilter] 인증이 완료되면 Authentication 객체를 SecurityContextHolder에 저장

  • 인증 성공 후 SecurityContext안에 인증객체(Authentication)를 저장하고
  • 이 SecurityContext를 다시 SecurityContextHolder에 저장합니다.
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
  • 후에 저장한 인증객체를 전역적으로 사용할 수 있게 됩니다.
Authentication authentication = SecurityContexHolder.getContext().getAuthentication();
  • SecurityContextHolder는 ThreadLocal에 저장되기 때문에 사용자마다 다른 SecurityContextHolder 인스턴스를 가집니다

 

용어 설명

AuthenticationManager

  • authenticate메서드(반환값은 Authentication객체) 하나를 가지고 있는 인터페이스
  • AutheticationManager는 인증을 처리하는 방법을 정의한 API이다.
  • AuthenticationFilter에 의해 AuthenticationManager가 동작한다.
  • 인증을 처리하면 SecurityContextHolder에 Authentication 값이 세팅된다.

ProviderManager 

  • AuthenticationManager(인터페이스)의 구현체
  • ProviderManager는 여러 개의 AuthenticationProvider를 가질 수 있다.
  • ProviderManager는 AuthenticationProvider 목록 중 인증처리 요건에 맞는 적절한 Provider를 찾아 인증처리를 위임하는 클래스

AuthenticationProvider

  • AuthenticationProvider는 인터페이스이며 두 개의 메서드가 제공된다.
  • authenticate(authentication) : 실제적인 인증처리를 위한 검증 메서드
    • UserDetailsService의 loadUserByUsername메서드를 통해 사용자 정보를 조회한다. (아이디 검증)
    • 반환받은 정보의 password와 인자로 받은 authentication의 password 정보를 비교한다 (비밀번호 검증)
    • 검증이 모두 성공하면 Authentication을 새로 생성, 반환한다. (검증여부가 true 체크된 Authentication 객체)
  • supports(authentication): 인증처리가 가능한 Provider인지 검사하는 메서드

UserDetailsService

  • 사용자 정보를 찾는 데 사용되는 loadUserByUsername메서드를 제공하는 인터페이스
  •  loadUserByUsername메서드는 username으로 사용자를 조회하여 UserDails로 반환해 준다.

Athenticateion

  • 사용자의 인증 정보를 저장하는 토큰 개념
  • 인증 성공 후 SecurityContextHolder안에 SecurityContext에 저장된다
  • SecurityContextHolder은 전역 객체 이기 때문에 인증객체(Athentication)를 전역적으로 사용할 수 있게 된다.
Athenticateion는  SecurityContext에 저장하고 이를 SecurityContextHolder라는 전역 객체 안에 저장하는데, 이 SecurityContextHolder는 ThreadLocal에 저장되기 때문에 각기 다른 스레드별로 다른 SecurityContextHolder 인스턴스를 가지고 있어서 사용자 별로 각기 다른 인증 객체를 가질 수 있습니다. 

 

Authentication 객체의 구조

  • principal: 사용자 아이디 혹은 User객체를 저장
  • credentials: 사용자 비밀번호
  • authorities: 인증된 사용자의 권한 목록
  • details: 인증 부가 정보
  • Authenticated: 인증 여부(Bool)

 

 

간단 정리

  • 요청이 들어오면 AuthenticationFilter는 전달받은 Username과 Password으로 인증객체(Authentication)를 만든다.
  • AuthenticationFilter -> AuthenticationManager(ProviderManager) 에게 인증처리 위임하고
  • AuthenticationManager  -> AuthenticationProvider에게 실제 인증처리를 위임한다.
    • AuthenticationManager의 구현체 ProviderManager는 가지고 있는 Provider 중에서 해당 인증객체를 검증할 수 있는 provider를 찾아 인증처리를 위임한다 
  • AuthenticationProvider는 UserDetailsService의 loadUserByUsername메서드를 활용하여 검증한다.
  • 인증 성공 후 SecurityContext안에 인증객체(Authentication)를 저장하고 이를 SecurityContextHolder에 저장한다.

 

 이렇게 전체적인 흐름을 정리해 보았고 다음 포스트에서는 코드를 살펴보며 자세하게 살펴보겠습니다.