[Spring Security] 웹 요청의 일반적 처리 흐름 / Spring Security 의 인증 & 권한 부여 처리 흐름
Spring Security에서 제공하는 컴포넌트들이
애플리케이션 내부에서 User의 인증, 권한에 대한 처리를 알아서 진행해준다! (filter chain)
but,
Spring Security 의 동작 방식을 조금 더 잘 알기 위해서는
각각의 흐름 잘 아는 것이 중요하다.
Spring Security 의 주요 기능이 1. 인증, 2. 인가(권한 부여) 이므로
이에 대한 흐름을 알아보도록 한다!
웹 요청의 일반적인 처리 흐름
(1)에서 사용자가 보호된 리소스를 요청
➡ 사용자 김보리가 A사이트의 그룹 B에 가입된 회원들만 볼 수 있는 글을 보려고 함
(2)에서 인증 관리자 역할을 하는 컴포넌트가 사용자의 크리덴셜(Credential)을 요청
* 사용자의 크리덴셜 = 신원 증명 정보 (password)
➡ 로그인을 해주세요!
(3)에서 사용자는 인증 관리자에게 크리덴셜(Credential)을 제공
➡ 사용자 김보리씨는 자신의 로그인, 패스워드를 입력함
(4)에서 인증 관리자 : 크리덴셜 저장소에서 사용자의 크리덴셜을 조회
➡ 크리덴셜 저장소에서 유저 김보리의 비밀번호 조회
(5)에서 인증 관리자는 사용자가 제공한 크리덴셜과 크리덴셜 저장소에 저장된 크리덴셜을 비교해 검증 작업을 수행
➡ 저장소의 비밀번호 = 김보리가 입력한 비밀번호?
(6) 유효한 크리덴셜이 아니라면 Exception을 throw합니다.
➡ 같지 않다면 '비밀번호가 틀립니다', 하면서 로그인 액세스 튕김
➡ 같다면 로그인 완료!
(7) 유효한 크리덴셜이라면 (8)에서 접근 결정 관리자 역할을 하는 컴포넌트는 사용자가 적절한 권한을 부여받았는지 검증합니다.
➡ 사이트 A에 가입만 하면 role 은 user,
사이트 내 특정 group 에 가입하면 group_user 일 경우
➡ Group B의 글은 role이 group_user 인 경우에만 볼 수 있다.
➡ 유저 김보리가 group_user 권한인지 검증
(9) 적절한 권한을 부여 받지 못한 사용자라면 Exception을 throw합니다.
➡ 김보리가 user 라면 'Group B 가입자만 볼 수 있는 글입니다' 하면서 거절됨
(10) 적절한 권한을 부여 받은 사용자라면 보호된 리소스의 접근을 허용합니다
➡ 김보리가 group_user 라면 리소스 읽기 가능
Spring Security 의 인증 처리 흐름
(1) 에서 사용자가 Username, Password 를 포함한 request 를 애플리케이션에 전송
사용자의 로그인 요청이 Spring Security 의 Filter Chain 까지 들어옴,
여러 Filter 들 중에서 UsernamePasswordAuthenticationFilter 가 해당 요청 전달 받음
(2) UsernamePasswordAuthenticationFilter ➡ Username, Password 가지고
UsernamePasswordAuthenticationToken 생성
* UsernamePasswordAuthenticationToken? : Authentication 인터페이스의 구현 클래스
Authentication 아직 인증 안된 것!
(3) UsernamePasswordAuthenticationFilter ➡ 아직 인증되지 않은 Authentication 을
AuthenticationManager 에게 전달
* AuthenticationManager : 인증 처리 총괄하는 매니저 역할 인터페이스
* ProvideManager : AuthenticationManager 의 구현 클래스
= 인증 작업 총괄하는 실질적 매니저!
= 인증을 직접하지 않고, 인증 처리를 AuthenticationManager 에게 맡긴 것
(4) AuthenticationManager : ProvideManager 로 부터 Authentication 전달 받음!
UserDetailsService 이용해서 UserDetails 조회
* UserDetailsService : UserDetails 를 제공하는 컴포넌트
UserDetails : db에 저장된 사용자의 Username, Credential(password), 권한 정보 포함하는 컴포넌트
(5), (6) UserDetailsService : db등의 저장소에서 사용자의 credential 포함한 정보 조회
(7) 조회한 사용자의 정보 기반으로 UserDetails 생성,
(8) 생성한 UserDetails 를 다시 AuthenticationProvider 에게 전달
AuthenticationProvider :
UserDetails 속 암호화된 password (password Encoder) = Authentication 속 password 맞는지 검증
(9) 검증 성공할 경우 : 인증된 Authentication 생성
검증 실패할 경우 : Exception 발생
(10) AuthenticationProvider : ProvideManager 에게 인증된 Authentication 전달
맨 처음 전달받은 인증 되지 않은 Authentication (로그인 정보)
≠
인증된 Authentication (인증에 성공한 Principal, Credential, GrantedAuthorities)
(11) ProvideManager : 인증된 Authentication 을 UsernamePasswordAuthenticationFilter 에 전달
(12) UsernamePasswordAuthenticationFilter :
SecurityContextHolder 를 이용해 SecurityContext에 인증된 Authentication 을 저장
* SecurityContext : 인증된 Authentication 객체를 저장하는 컴포넌트
* SecurityContextHolder : SecurityContext 관리
⬇
해당 과정을 마치고 나면, '인증된 사용자'임이 확인 된 것이다!
(SecurityContextHolder 에 의해 SecurityContext 에 값이 채워져 있다? = 인증된 사용자)
but 인증된 사용자라고 해서 애플리케이션에서 제공하는 리소스를 마음대로 이용할 수는 없다!
Spring Security 에서 어떤 과정을 거쳐 애플리케이션 리소스에 대한 접근 권한을 부여하는지 흐름 확인
Spring Security 의 권한 부여 처리 흐름
AuthorizationFilter : Spring Security Filter Chain 에서 URL 을 통해 사용자의 액세스 제한하는 권한 부여 Filter
(1) AuthorizationFilter : SecurityContextHolder 로 부터 Authentication 획득
(2) AuthorizationFilter ➡ AuthorizationManager 에게
Authentication, HttpServletRequest 전달
* AuthorizationManager : 권한 부여 처리 총괄 매니저
RequestMatcherDelegatingAuthorizationManager : AuthorizationManager 구현체 중 하나
⬇
RequestMatcher 평가식 기반으로 AuthorizationManager 에게 구현 부여 처리를 위임한다!
*RequestMatcher = SecurityConfiguration 속
antMatchers("/orders/**").hasRole("ADMIN") 와 같은 메서드 체인 정보 기반으로 생성됨
(3) 매칭되는 AuthorizationManager 구현 클래스에게 위임을 함 - 해당 구현 클래스가 사용자의 권한 체크
(4) 적절한 권한일 경우 요청 프로세스 이어나감
(5) 어긋난 권한이라면 AccessDeniedException 처리! (by ExceptionTranslationFilter)