느리더라도 꾸준히

Section4 - Spring Security 회고록 본문

(CodeStates)Daily memoir

Section4 - Spring Security 회고록

테디규 2023. 2. 1. 10:31

지금까지의 회고록

Spring Security를 처음 배워봤는데, Default로 ? 자동으로 동작하는 프레임워크에 원하는 기능을 위해 조금씩 수정해야하는 방식으로 사용해야함을 알았다. 큰 흐름동작이나 로직들은 이해할 수 있었으나, 세부적으로 코드가 어떻게 동작하는지 까지의 로직은 시간적 제한이 있기에 이해하지 못하겠다. 이는 천천히 프로젝트를 하다보면 늘 수 있을테니, 얼른 프로젝트에 Security를 적용해봐야 할 것 같다.

Spring Security란?

Spring MVC 기반 애플리케이션의 인증(Authentication)과 인가(Authorization or 권한 부여) 기능을 지원하는 보안 프레임워크로써, Spring MVC 기반 애플리케이션에 보안을 적용하기위한 사실상의 표준이 되었다.

왜 Spring Security를 사용하는가?

  1. 밑바닥부터 보안을 모두 설계하고 구현하는 것은 매우 어려운 작업이다.
  2. 애플리케이션의 보안을 강화하기 위한 솔루션으로 Spring Security만한 프레임워크가 존재하지 않는다.
  3. 대부분의 보안 문제의 경우 Spring Security Framework에서 지원하는 기본 옵션을 통해 보안 요구사항을 만족시킬 수 있다.
  4. 기본 옵션으로 만족 시킬 수 없는 특정 보안 요구 사항을 만족시켜야 할 경우, Spring Security를 사용하면 특정 보안 요구 사항을 만족시키기 위한 커스터마이징이 용이하고 유연한 확장이 가능하다.

Spring Security의 기본 구조 이해하기.

  1. 의존 라이브러리를 추가해준다.
  2. App 을 실행시킨다.
  3. 로그인 인증을 시도한다.

→ 이때 Spring Security는 수많은 Bean들의 상호 작용을 통해 동작한다.

해당 Bean들은 특별히 값을 지정해주지 않으면 Default 된 값으로 동작한다. 우리가 Spring Security를 제대로 이용하기 위해서는 이 Bean들이 제공하는 기능을 부분 부분 수정할 수 있어야한다.

@Configuration이 적힌 클래스(SecurityConfiguration) 아래에서 @Bean이 붙은 메서드로 선언하여 설정 값을 지정해 줄 수 있다. 이때 Spring Container에는 중복된 타입이 들어가지 않도록 주의해야한다.

( Spring Security가 사용할 Bean을 구별할때 Bean 타입으로 구분함을 기억하자.)

대표적으로 인증/인가에 사용되는 Bean들은 다음과 같다. 이러한 Bean들은 Spring Security에서 자동으로 동작할 수도 있지만, 우리가 따로 Custom으로 구현해 줄 수도 있다.

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfigurationV2 {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{...}

    @Bean
    public UserDetailsManager userDetailsService(){...}

    @Bean
    public PasswordEncoder passwordEncoder(){...}
  • Bean type : UserDetailsManager
    • 사용자의 핵심 정보(UserDetails)를 관리해주는 Bean이다.
  • Bean type : SecurityFilterChain
    • 여러 Filter들을 통해 HTTP 보안 설정을 관리하는 Bean이다.
    • 인증에 필요한 Filter 부터 인가에 필요한 Filter까지 존재한다.
  • Bean type : PasswordEncoder
    • 문자열 값을 암호화된 값으로 바꾸어 비교할 수 있도록 해주는 Bean이다.

또한 AuthenticationProvider 처럼 구현체를 생성해줌으로써 Security에 Custom으로 인증 처리를 생성해 줄 수도 있다.

@Component
public class HelloUserAuthenticationProvider implements AuthenticationProvider {...}

회원 가입

Spring Security 인증이 성공적으로 처리되려면, 인증 단계 이전에 회원 정보가 InMemory 또는 DB에 저장되어있어야한다.

그래야 로그인 인증시의 (인증되지 않은) 정보와 저장소에서 조회한 인증된 정보를 비교한 후, 인증처리를 마친후 해당 User에게 알맞은 권한(Authorization)을 제공할 수 있기 때문이다.

일반 적으로 회원 가입은 User가 제공한 인증 정보를 DB나 메모리에 저장한 후, 필요시 조회만 해오면 된다. 그러나 Spring Security에서의 회원 가입은 더 많은 흐름대로 흘러간다.

[Form 회원 가입 및 로그인시 인증 흐름]

  • 회원 가입 로직(2) 회원 인증 정보를 InMemory DB H2 에 저장
  • (1) Form을 통한 회원가입 - 인증 정보 입력
  • 로그인 동작(3)로그인 인증시점에 DB에서 회원 인증 정보를 조회한 후, UserDetailsManager 에 User(UserDetails) 객체를 저장
    • 인증 객체(UserDetails)를 생성하기 위해 (1)로 얻은 정보를 토대로 **식별자, 암호화된 PW, 권한 정보**의 구조의 인증된 객체를 생성한다.
    (4)인증된 객체를 통해 인증 처리
  • (5) 로그인 완료!
  • Spring Security Framework를 통해 자동으로 인증 및 인가가 동작한다.

Spring Security 인증 구성 요소 이해

Spring Security Framework의 Default 정보로 프레임워크가 동작할때 어떤 인증 구성 요소들을 통해 인증 흐름이 완성 되는지 정리해보자.

  1. 클라이언트가 Username, password를 통해 인증한다.
    • 여기서 Username은 User를 식별해주는 이메일이나, ID등을 적는다.
  2. (IF)AbstractAuthenticationProcessingFilter ****의 구현체인**** UsernamePasswordAuthenticationFilter를 통해 (IF)Authentication 객체인 UsernamePasswordAuthenticationToken을 생성한다.
    • IF : 인터페이스를 의미
  3. 해당 토큰 정보를 매개변수로 하여 (IF)ProviderManager에게 (인증 객체 생성의 역할을) 위임한다.
  4. (IF)ProviderManager의 Default 구현체인 AuthenticationManager에서 (IF) AuthenticationProvider****에게 (인증 객체 생성의 역할)****을 위임한다.
  5. (IF) AuthenticationProvider의 구현체 중 Username/Password 기반의 인증 처리를 담당하는 DaoAuthenticationProvider에서 인증 객체를 생성하거나 예외를 발생시킨다.
    1. 위임을 통해 매개변수로 전달 받은 UsernamePasswordAuthenticationToken 과 DB정보를 통해 생성한 UserDetails 를 서로 검증한다.
    2. 검증이 성공한다면, 해당 UserDetails 를 통해 인증된 Authentication 객체를 생성한 후 , 반환한다. → ProviderManager에게 전달된다.
    3. 검증이 실패한다면, 예외를 발생시킨다.
  6. 인증된 Authentication 객체는 ProviderManager → UsernamePasswordAuthenticationFilter → SecurityContextHolder를 통해 SecurityContext에 저장된다.
    • 이와 동시에 UsernamePasswordAuthenticationFilter 의 인터페이스인 AbstractAuthenticationProcessingFilter에서 dofilter()가 동작하여 다음 필터로 넘어간다.

Spring Security 권한 부여 구성 요소 이해

권한 부여가 어떤 순서로 되는지 이해해보자.

  1. 인증 흐름에 따라 생성된 (SecurityContextHolder를 통해 SecurityContext에 저장된) Authentication 객체를 가져온다.
  2. Authentication 객체는 Authorization Filter를 통해 AuthorizationManager 의 구현체인 RequestMatcherDelegatingAuthorizationManager로 권한 부여 역할을 위임한다.
  3. RequestMatcherDelegatingAuthorizationManager는 RequestMatcher 에게 권한 부여 역할을 위임한다.
    • 이때 RequestMatcher는 Security Configuration 에서 설정한 권한 부여 관련 메서드 체인에 의해 생성된다.
    • 만약 RequestMatcher 가 검증한 결과들이 모두 참이 나온다면, Authentication객체에 권한들을 추가해준다.
    • 만약 RequestMatcher 가 검증한 결과중 거짓이 나온다면, 예외를 발생시킨다.
Comments