Easy Understanding

Spring Security 뼈대 정리(Tomcat에서 Spring 까지의 처리 과정) 본문

Study

Spring Security 뼈대 정리(Tomcat에서 Spring 까지의 처리 과정)

appleg1226 2021. 7. 12. 17:20

1. Security의 목적

Spring Security 모듈은 말 그대로 어플리케이션을 'Secure(안전)'하게 유지시키기 위한 모듈이다.

보통 비밀번호나 키 들을 이용해서 접근을 통제하거나(Authentication),

접근하는 사람의 신분이 User인지 Admin인지 등에 따라 제한된 권한을 주기도 한다.(Authorization)

 


2. 어떤 기술을 기반으로 하는가

Spring은 일반적으로 '웹' 서버를 만드는 데 사용이 된다.

웹 서버는 일반적으로 웹 요청이 들어왔다가(Request), 원하는 정보를 얻어 나가는 형태(Response)로 동작한다.

Spring Security는 들어오는 중에, 웹 요청을 앞에서 미리 방어하는 식으로 구현되어 있다.

정확하게 이런 식으로 구현되어 있지는 않지만, 대략적으로 위의 그림과 같은 느낌이라고 보면 된다.

1) Tomcat에서 웹 요청을 받아서 그것을 Spring에 처리하도록 보내려고 한다.

2) Spring Security에서 방패처럼 그 요청을 막아선다. 여기에서 요청을 확인 후 Spring으로 보낼지 말지 결정한다.

3) Spring Security에서 승인했다면 Spring에서 로직을 수행하여 사용자에게 반환한다.

 

이렇게 요청을 미리 확인하고 막는 것을 스프링에서는 'Filter'라는 기술을 이용하여 구현한다.

위의 그림의 방패가 즉 Filter가 되는 것인데, 자세한 것은 아래에서 설명하도록 하겠다. 

 


3. 대략적인 그림

아래의 그림은 Spring Security 공식 문서에 표현되어 있는 Spring Security의 전체적인 아키텍쳐다.

 

출처: Spring Security 공식 문서

1) 가장 먼저 Client에서 요청을 날리면 그 요청을 Tomcat에서 받는다.

 

2) Tomcat에는 여러 Filter가 존재하지만, Spring에 작성된 DelegatingFilterProxy를 자신의 Filter 중 하나로 등록한다.

 

3) DelegatingFilterProxy는 내부적으로 스프링의 Bean인 FilterChianProxy를 사용한다

 

4) FilterChainProxy는 내부적으로 Filter들의 묶음인 SecurityFilterChain을 사용한다.

 

5) 이 필터들을 다 거치면 Servlet(정확하게는 DispatcherServlet)으로 요청이 성공적으로 전달된다.

 


4. 세부 설명 

1) DelegatingFilterProxy

가장 먼저 DelegatingFilterProxy 라는 클래스가 있는데, 이건 Tomcat과 같은 인터페이스를 구현한 Filter이다.

그래서 구현은 스프링에 되어있지만, Tomcat에서 이 DelegatingFilterProxy를 자신의 필터로 등록한다.

 

비유하자면, Spring이 Tomcat에게 제물로 바친 Filter이다.

그래서 DelegatingFilterProxy는 Tomcat의 소유가 되어 Tomcat의 필터로 행동한다.

 

2) FilterChainProxy

DelegatingFilterProxy는 Tomcat의 소유가 되었기 때문에, 내부적으로 Spring을 잘 아는 Filter가 하나 더 필요하다.

징검다리를 하는 역할이 FilterChainProxy이다. 

 

게다가 이건 Spring의 Bean으로도 등록이 되어있다.

이제 실질적인 Filtering은 이 FilterChainProxy에서 처리하게 될 것이다.

 

추가적으로 다음에 나올 SecurityFilterChain들을 내부에 갖고 있는데,

url등 사용자의 조건에 따라서 어떤 것을 사용할지도 결정할 수 있다.

 

3) SecurityFilterChain

Tomcat이 겉에서 보기에는 DelegatingFilterProxy 하나 밖에 안 보이겠지만,

이제 안에서는 Spring만의 여러 개의 Filter들이 일하기 시작한다.

 

스프링에 등록되어 있는 각종 필터들은 이 SecurityFilterChain에 저장이 된다.

(이 SecurityFilterChain의 내부에서는 Filter들을 List<Filter>로 관리하고 있다.)

private final List<Filter> filters;

 

게다가 위의 그림을 보면 알 수 있지만, url 에 따라서 다른 SecurityFilterChain을 사용하게 된다.

 

여기에는 다양한 필터들이 설정되어 있다.

예시를 들면 다음과 같은 필터들이 있다.

- CorsFilter(CORS를 담당)
- UsernamePasswordAuthenticationFilter(Authentication을 담당)
- BasicAuthenticationFilter(Authentication을 담당)
- RememberMeAuthenticationFilter(Session, Cookie쪽을 담당)
- FilterSecurityInterceptor(Authorization을 담당)

 

이제부터 구체적인 Authentication, Authorization 과정이 시작되는 것이다.

 

정리하자면,

 

- DelegatingFilterProxy: Spring에서 바치는 Tomcat에 저장될 필터. 

- FilterChainProxy: 그 안에 들어가서 실제로 Spring Security를 관리하는 실세

- SecurityFilterChain: FilterChainProxy가 관리하는 Filter들의 모음들

라고 정리해 볼 수 있겠다.

 

4) Filter가 구현된 방식

추가로 FilterChainProxy에서 SecurityFilterChain들을 동작시키는 방식이 좀 세련되어서 정리해 보려고 한다.

코딩테스트에서만 사용했었던 재귀가 여기에서 사용된다.

 

모든 Filter 클래스들을 보면 다 내부에 아래와 같은 메서드가 존재한다.

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)

재귀적으로 동작시킬 수 있는 핵심은 FilterChain이라는 것 덕분이다.

FilterChaindoFilter()라는 메서드를 내부적으로 갖고 있기 때문에,

계속 chain을 재사용하면서 내부적으로 이런 식으로 동작을 충분히 시킬 수가 있다.

doFilter(..., FilterChain chain){
  chain.doFilter(..., FilterChain chain){
    chain.doFilter(..., FilterChain chain){
      chain.doFilter(..., FilterChain chain){
        chain.doFilter(){
          ....
        }
      }
    }
  }
}

 

자세한 구현은 FilterChainProxy 내부의 VirtualFilterChain 클래스를 살펴보면 된다.

Debugger를 FilterChainProxy의 doFilter()에 찍어서 재귀 호출을 확인하면 좋다.

 


5. 다른 언어의 사례

다른 언어도 크게 다르지는 않다.

Node.js 에는 Middleware라는 것이 존재하는데,

이 Middleware의 원리도 request(req)를 요청 전에 확인해서, 다음으로 전달하는 것이다.

이름만 다르지 filter와 크게 개념적으로 다르지는 않다.

var express = require('express');
var app = express();

var myLogger = function (req, res, next) {
  console.log('LOGGED');
  next();
};

app.use(myLogger);

 

myLogger 함수가 Spring Security의 doFilter()와 크게 다르지 않은 것을 확인할 수 있다.

 


6. 마무리

이후에 이루어지는 Authentication, Authorization 과정은 이번 정리에서는 제외했다.

이번 스터디에서는 Spring Security가 Spring Web과 연관하여,

구현이 어떤 방식으로 되나에 대한 궁금증을 해결할 수 있었다.