[Spring Security] 내부 흐름

minseok Kim·2025년 1월 14일

Spring Security

목록 보기
3/15

이번 포스트에서는 Spring Security가 내부적으로 어떤 과정을 통해 보안 기능을 제공하는지 정리해 보았다.


Spring Security은 위 사진과 같은 흐름을 가지고 작동한다.
각 단계에서 어떤 일이 발생하는지, 각 구성요소가 하는 역할이 무엇인지를 이해하기 위해 자세하게 흐름적으로 정리해보았다.



1단계

클라이언트 어플리케이션, 포스트맨 등을 통해 End User가 REST API, MVC path에 접근하기 위해 요청을 보낸다.

만약 보호된 API에 접근하기 위해선 우리가 설정한 구성에 따라 RequestHeader, RequestBody에 자격 증명을 제공해야 한다.

자격 증명 없이 보호된 API에 접근한다면, 앞서 확인했던 것 처럼 Spring Security는 사용자를 로그인 페이지로 redirect한다.

사용자가 인증되었는지의 여부는 Spring Security Filter가 담당한다.
Spring Security는 보안 기능을 제공하기 위한 여러 개의 Filter를 가지고 있다.
Filter는 각 요청을 가로채고 각 Filter는 보안을 위한 책임을 갖는다. 사용자 인증, CSRF 공격 방지 등의 여러 Filter가 존재한다.
예를 들어 사용자가 인증되지 않았다면, 해당 책임을 갖는 Filter가 사용자를 로그인 페이지로 redirect 한다.

중요한 점은 사용자가 보호된 백엔드 API에 request를 보내는 즉시, 해당 요청은 Spring Security Filter에 의해 가로채진다는 점이다.
요청에 대해 각 Filter는 차례차례 해당 request를 검사하고, 어느 Filter에서든 문제가 발생하면 사용자는 401/403 에러를 받게 된다.


2단계

만약 사용자가 request에 올바른 자격 증명을 제공했다면, Spring Security Filter가 Authentication 객체를 채운다.

사용자로부터 받은 자격 증명은 HTTP request 객체 내에 있기 때문에, Spring Security Filter의 첫 번째 책임은 자격 증명을 HTTP Request Servlet 객체에서 Authentication 객체로 변환하는 것이다.

이 Authentication 객체에는 username, password, isAuthenticated(사용자가 인증되었는지) 등의 정보를 담는다.
이렇게 Authentication 객체가 채워지면 해당 객체 정보는 Spring Security의 전 과정에서 사용된다.


3단계

Authentication 객체가 채워지면 request를 Authentication Manager에게 전달할 Filter가 작동한다.

Authentication Manager인증이 성공했는지 여부에 관계없이 인증을 완료하고 그 결과를 Filter로 다시 전달하는 책임을 맡는다.
즉, Authentication Manager가 하는 역할은 Authentication 객체를 받고 다른 요소들의 도움을 받아 사용자를 인증하는 책임을 지는 것이다.

Authenticaton Manager는 인증을 완료하는 책임만 지고, 실제 인증은 진행하지 않는다.


4단계

실제 인증을 위해서 Authentication Manager는 Authentication Provider에게 request를 전달한다.

인증 역할을 하는 Authentication Manager는 여러 종류가 있고, 사용자가 직접 정의할 수도 있어 하나의 프로젝트에 여러 두 개 이상의 Authentication Manager가 존재할 수 있다.

따라서 Authentication Manager의 책임은 모든 적용 가능한 Authentication Provider를 확인하여 인증이 성공했는지 실패했는지를 식별하는 것이다.


5단계

Authenticaton Provider가 인증을 위해 Authentication 객체를 받으면, UserDetailsManager, UserDetailsService의 도움을 받아 인증 과정을 진행한다.


6단계

이러한 UserDetailManagerPasswordEncoder의 도움을 받는다.

Authentication Provider가 Authentication 객체를 받을 때 가장 먼저 하는 일은 username을 통해 UserDetails을 로드하는 것이다.
이 때 UserDetailManager/UserDetailService의 도움을 받아 UserDetails 정보를 가져온다.

UserDetails을 가져오면, 다시 Authentication Provider로 전송된다.

Authentication Provider는 자체적으로 사용자가 입력한 비밀번호와 DB/메모리에 있는 비밀번호를 비교하지 않는다. 비밀번호가 동일한지에 대한 비교는 PasswordEncoder의 도움을 통해 진행된다.
즉, PasswordEncoder의 역할은 비밀번호를 비교하는 것이다.

Authentication Provider는 UserDetailsManager에게 PasswordEncoder를 통해 사용자가 제공한 비밀번호가 DB에서 로드된 비밀번호를 비교하도록 요청한다.


7단계

PasswordEncoder비밀번호가 일치한다고 확인하면, Authentication ProviderAuthentication Manager에게 인증이 성공했다고 전달한다.

인증이 성공했다고 전달시, Authentication 객체에 값이 true인 isAuthenticated을 포함한다.
이 값을 기반으로, Authentication Manager는 인증이 성공했는지의 여부를 알 수 있다.


8단계

이후 동일한 Authentication 객체가 Spring Security Filter로 다시 전송된다.


9단계

Spring Security Filter는 인증이 성공했는지 여부를 알게 되고, 인증의 성공 여부와는 무관하게 인증 정보가 Security Context에 저장된다.

해당 Authentication 객체는 주어진 브라우저에 대해 생성된 session ID에 따라 저장된다.

따라서, 사용자가 동일한 브라우저에서 동일한 보호된 페이지에 접근하려고 하면 주어진 세션ID를 기반으로 Spring Security Filter는 Security Context에서 인증 정보를 로드하고, 이에 따라 성공/에러 메시지를 표시한다.

즉, 실제 인증 과정첫 번째 요청에 대해서만 발생하고(Security Context에 주어진 세션ID에 대한 내용이 없으므로), 이후의 요청은 Security Context의 정보를 활용한다.

Security Context에 해당 세션ID에 대한 정보가 있다면, 다음부터는 Spring Security Filter가 Authentication Manager를 호출하지 않는다. 대신 Security Context를 확인하여 성공/에러 response를 보낸다.


10단계

마지막으로 클라이언트 애플리케이션에 응답을 보낸다.
인증이 성공한 경우, REST API로부터 응답을 받게 되고,
인증이 실패한 경우, 401 또는 403 에러를 받게 된다


각 컴포넌트 정리

마지막으로 Spring Security에서 각 컴포넌트들이 어떤 역할을 하는지 간단히 정리해봤다.

Spring Security Filter

  • 각 request를 가로채고 Authentication이 필요한지 여부를 확인한다. 인증 과정이 필요하다면, 사용자를 로그인 페이지로 이동시키거나 초기 인증 시 저장된 세부 정보를 사용한다.

Authentication

  • UsernamePasswordAuthenticationFilter와 같은 Filter가 HTTP request로부터 username/password를 뽑아내고, 이를 Authentication 객체로 변환한다.

AuthenticationManager

  • AuthenticationManager가 filter로부터 request를 받으면, user detail의 검증을 AuthenticationProvider에게 위임한다. 하나의 프로젝트 안에 여러 AuthenticationProvider가 있을 수 있으므로, 가능한 모든 AuthenticationProvider를 관리하는 것이 AuthenticationManager의 역할이다.

AuthenticationProvider

  • 인증을 위해 user detail을 검증하는 역할을 한다.

UserDetailsManager/UserDetailsService

  • UserDetailsManager/UserDetailsService는 DB/저장소에서 User Details을 검색, 생성, 업데이트, 삭제하는 역할을 한다.

PasswordEncoder

  • password encoding & hasing하는 역할을 하는 인터페이스이다. password는 plain text로 저장되면 안되기에, PasswordEncoder를 사용한다.

SecurityContext

  • 한번 request가 인증되면, 해당 Authentication은 SecurityContextHolder에 의해 SecurityContext에 저장된다.

0개의 댓글