Spring/Spring Security

[Spring Security] 웹 요청의 일반적 처리 흐름 / Spring Security 의 인증 & 권한 부여 처리 흐름

jungha_k 2022. 11. 22. 15:08

 

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)