Spring Security 구조 알아보기

subbni·2023년 4월 12일

참고 : https://docs.spring.io/spring-security/reference/servlet/architecture.html


스프링 시큐리티 구조

- Servlet Container를 도식화한 그림

  • 클라이언트 -> HttpServletRequest->FilterChain->DispatcherServlet->HttpServletResponse->FilterChain->클라이언트
  • 필터는 HttpServletRequest,HttpServletResponse를 수정할 수 있다.
  • FilterChain이 각 필터를 순서대로 호출하고, 호출 할 때 respons, request 인스턴스를 주입한다.
  • 필터에 의해 response, request가 변경 될 수 있으므로 필터의 순서는 중요하다.

DelegatingFilterProxy

  • FilterChain 각 필터를 호출할 때, 바로 필터를 호출하는 것이 아니라 DelegatingFilterProxy를 호출한다. 개발자가 직접 작성하여 Bean으로 만든Bean Filter는 ApplicationContext에 존재하고 서블릿 컨테이너가 이를 가져오는 작업이 필요한데, 이 역할을 DelegatingFilterProxy가 한다.

    DelegatingFilterProxy
    : ApplicationContext에서 Bean Filter를 가져온 후, 실행시켜 모든 작업을 해당 필터에게 위임한다.


FilterChainProxy

SpringSecurity를 support하는 서블릿들은 FilterChainProxy라는 빈 필터 안에 들어있다. FilterChainProxy는 Spring Security가 제공하는 많은 필터들,SecurityFilterChain의 delegate를 돕는 필터이다.

즉,
DelegatingFilterProxy > FilterChainProxy > SecurityFilterChain > 여러 개의 Filters...

그렇지만 왜 DelegatinFilterProxy에서 바로 delegating하지 않고 FilterChainProxy를 한 번 더 거치는 걸까?
1. 디버깅에 용이 > Spring Security Sevlet의 시작점은 무조건 'FilterChainProxy'임으로 디버깅시 디버깅 포인트를 잡기 쉬움
2. 여러가지 다른 option들 사용 가능 ex) SecurityCOntext의 메모리 누수 피하기, HttpFirewall 기능 등
3. SecurityFilterChain의 실행을 더 유연하게 제어할 수 있다. > Sevlet container에 의해서 제어되는 Filter들은 오직 URL에만 근거되어 Filter가 실행됨. 그렇지만 FilterChainProxy에서는 ReqeustMather를 사용하여 HttpServletRequest내의 다향한 정보에 근거하여 Filter 실행을 결정할 수 있다.


SecurityFilterChain


FilterChainProxy가 이제 SecurityFilterChain 중에서 어떤 것을 실행할 지를 결정한다.

  • 제일 먼저 매치되는 첫 번째 SecurityFilterChain만이 실행된다. 예를 들어 위 그림에서 url이 /api/messages/ 로 들어왔다면, SecurityFilterChain 𝙣과 바로 매치되므로 만약 뒤에 또 매치되는 필터가 있다하더라도 이 필터 체인 하나만 실행된다.
  • 만일 그 어떤 다른 SecuiryFilterChain과 매치되지 않는다면 '/**'인 SecuiryFilterChain 𝘯이 실행된다.
  • SecurityFilterChain는 unique하다.
  • SecurityFilterChainFilter를 가지고 있지 않을 수 있으며, 이 경우 해당 체인에 매치되는 요청에 대해서는 무시하게 된다.

Security 예외 처리

  • ExceptionTranslationFilter는 Security Filters 중의 하나이다.
  • ExceptionTranslationFilter가 예외를 catch해서 HTTP response에 해당 예외를 넣어 전송하는 등의 역할을 한다.

더 자세히 알아보자 . . .

1. 만일 user가 인증되어 있지 않거나 AuthenticationException 이 발생할 경우
: 인증 자체가 안 되어 있는 경우

  • 인증 절차(로그인)를 시작한다.
  • SecurityContextHolder를 비운다.
  • HttpServletRequest는 인증이 끝난 뒤 다시 사용하기 위해 ReqeustCache에 저장한다.
  • AuthenticationEntrypoint에서 client에 credentails를 요청한다. (로그인 페이지로 redirect 시키거나 아님 HTTP response로 에러 넣어서 날리거나 하면 되는 듯?)

2. 만일 AccessDeniedException이 발생한 경우
: 인가되지 않은 사용자일 경우 (자격이 없는 경우)

  • AccessDeniedHandler가 작동된다

profile
개발콩나물

0개의 댓글