[ 정수원 스프링 시큐리티 #2 ] 스프링 시큐리티 주요 아키텍처 이해 (3)

김수호·2024년 3월 14일
0
post-thumbnail

지난 포스팅에 이어, 이번 포스팅에서는 6) ~ 8) 의 내용을 정리한다.

👉 목차는 다음과 같다.

1) 위임 필터 및 필터 빈 초기화 - DelegatingProxyChain, FilterChainProxy
2) 필터 초기화와 다중 보안 설정
3) 인증 개념 이해 - Authentication
4) 인증 저장소 - SecurityContextHolder, SecurityContext
5) 인증 저장소 필터 - SecurityContextPersistenceFilter
6) 인증 흐름 이해 - Authentication Flow
7) 인증 관리자 : AuthenticationManager
8) 인증 처리자 : AuthenticationProvider

9) 인가 개념 및 필터 이해 : Authorization, FilterSecurityInterceptor
10) 인가 결정 심의자 : AccessDecisionManager, AccessDecisionVoter
11) 스프링 시큐리티 필터 및 아키텍처 정리

바로 하나씩 확인해보자.


6) 인증 흐름 이해 - Authentication Flow

이번 내용에서는 스프링 시큐리티에서 인증을 처리하는 전반적인 흐름을 정리해보자.

  • 참고) Authentication Flow
    • 1) 클라이언트가 폼 로그인 인증을 요청한다.
    • 2) 폼 인증 방식의 인증 처리를 하는 필터인 UsernamePasswordAuthenticationFilter 에서 사용자의 인증 요청을 받는다. 그리고 해당 필터는 사용자가 로그인시 입력한 id 와 password 정보를 추출해서 이를 기반으로 인증 객체를 생성한다. 그리고 AuthenticationManager 에게 인증 객체를 전달하면서 인증 처리를 맡긴다.
    • 3) AuthenticationManager 는 내부에서 관리하는 AuthenticationProvider 객체들 중에서 현재 사용자의 인증 요청을 처리할 수 있는 적절한 객체를 찾고, 해당 객체에게 인증 처리를 위임한다.
    • 4) AuthenticationProvider 는 사용자가 인증시 요청한 id, password 와 같은 정보들이 유효한지를 검증하는 등 실제 인증을 처리하는 역할을 한다.
      • 참고) 사용자가 인증시 입력한 아이디를 스프링 시큐리티에서는 username 이라고 표현한다.
      • 검증 과정은 다음과 같다.
        • ID 검증
          • UserDetailsService 에게 username 을 전달하면서, UserDetails 타입의 객체를 요청한다. ( loadUserByUsername(username) )
          • UserDetailsService 는 username 에 해당하는 사용자 정보를 데이터 계층으로부터 조회해서 UserDetails 타입으로 반환한다.
            • 만약 사용자 정보가 존재하지 않으면, UsernameNotFoundException 예외를 발생시킨다. 그리고 해당 예외는 이후 인증 필터에서 받아서 처리한다. ( failureHandler 를 통해 실패와 관련된 후속처리를 하는 등 )
        • password 검증
          • AuthenticationProvider 는 UserDetailsService 로 부터 반환받은 UserDetails 타입의 객체에 저장된 패스워드 정보와, 사용자가 인증시 입력한 패스워드 정보가 일치하는지 검증한다.
            • 만약 패스워드가 일치하지 않으면, BadCredentialsException 예외를 발생시킨다. 그리고 해당 예외는 이후 인증 필터에서 받아서 처리한다. ( failureHandler 를 통해 실패와 관련된 후속처리를 하는 등 )
        • 추가 검증
          • 추가적으로 필요한 검증을 진행한다.
      • 검증 과정을 모두 통과하면 인증 검증에 성공한 것이므로, AuthenticationProvider 는 인증 결과 정보를 저장하기 위한 Authentication 객체를 생성해서, UserDetails 객체와 authorities 권한 정보 등을 담는다. 그리고 이를 AuthenticationManager 에게 반환한다.
    • 5) AuthenticationManager 는 AuthenticationProvider 로 부터 전달받은 Authentication 인증 객체를 다시 UsernamePasswordAuthenticationFilter 에게 반환한다.
    • 6) UsernamePasswordAuthenticationFilter 는 전달받은 인증 객체를 SecurityContext 객체에 저장한다.

7) 인증 관리자 : AuthenticationManager

이번 내용에서는 인증 관리자(AuthenticationManager)에 대해서 알아보자.

  • 참고) AuthenticationManager
    • AuthenticationManager 는 인증 필터로부터 인증 처리를 지시받는다.
      • 참고) AuthenticationManager 는 인터페이스이고, 이를 구현한 구현체가 ProviderManager 이다.
    • ProviderManager 는 자신이 관리하는 AuthenticationProvider 목록 중에서 사용자의 인증 요청을 처리할 수 있는 적절한 AuthenticationProvider 객체를 찾아서 인증 처리를 위임한다.
    • 부모 ProviderManager 를 설정하여 AuthenticationProvider 를 계속 탐색할 수 있다.
      • 만약 ProviderManager 자신이 가지고 있는 AuthenticationProvider 목록 중에서 현재 인증을 처리할 수 있는 AuthenticationProvider 가 없으면, (AuthenticationManager 타입의) parent 속성에 저장되어 있는 AuthenticationProvider 목록을 탐색한다. 만약 그곳에 현재 인증을 처리할 수 있는 객체가 있다면, 그 객체에게 인증 처리를 위임한다.
  • 참고) AuthenticationManager 응용
    • Linked 형태로 부모와 자식간의 관계를 형성할 수 있다.
    • 자식에서 적절한 AuthenticationProvider 를 찾지 못할 경우 계속 부모로 탐색하여 찾는 과정을 반복한다.
    • AuthenticationManagerBuilder 를 사용해서 스프링 시큐리티의 초기화 과정에서 설정한 기본 Parent 관계를 변경해야 권한 필터에서 재 인증 시 모든 AuthenticationProvider 를 탐색할 수 있다.

 

✔️ 참고


8) 인증 처리자 : AuthenticationProvider

이번 내용에서는 실질적으로 인증 처리를 할 때 가장 핵심적인 역할을 하는 AuthenticationProvider 에 대해서 알아보자.

  • 참고)
    • 참고) AuthenticationProvider 는 인터페이스이고, 스프링 시큐리티가 기본적으로 제공하는 구현체들이 몇 가지 있다. 보통은 해당 인터페이스를 직접 구현해서 우리의 시스템에 맞도록 인증 처리를 할 수 있도록 구현한다.
    • AuthenticationProvider 는 두 개의 메서드가 제공된다.
      • authenticate(authentication) : 인증 처리를 위한 검증을 진행한다.
      • supports(authentication) : 사용자의 인증 요청을 자신이 처리할 수 있는지 여부를 체크한다.
      • 참고) 파라미터로 전달받는 authentication 객체는 사용자가 인증시 입력한 아이디와 패스워드 정보를 담고 있는 인증 객체이다.
    • authenticate(authentication) 메서드에서 처리하는 검증 절차는 다음과 같다.
      • 1) ID 검증 : 사용자가 입력한 아이디 정보가 실제 존재하는지 여부를 체크한다. 이때, UserDetailsService 를 통해, 데이터 계층으로부터 사용자 정보를 조회해서 UserDetails 타입으로 전달받는다.
        • 만약, 사용자 정보가 존재하지 않을 시 UsernameNotFoundException 이 발생한다.
      • 2) password 검증 : UserDetails 타입의 객체에 저장된 패스워드 정보와 사용자가 입력한 패스워드 정보가 일치하는지 여부를 체크한다.
        • 만약, 일치하지 않을 시 BadCredentialException 이 발생한다.
        • 참고) PasswordEncoder 를 사용해서 비교한다.
      • 3) 추가적인 검증 : 추가적으로 필요한 검증을 진행한다.
    • 검증 절차를 모두 통과하게 되면, 최종적으로 인증에 성공한 사용자의 정보(User, authroties)를 담은 인증 객체를 생성해서 AuthenticationManager 에게 전달한다.

강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 정수원 강사님께 있습니다.

profile
현실에서 한 발자국

0개의 댓글