Spring Security 동작 원리 이해하기
이 글은 다른 글들을 짜집기하여 본인의 Spring Security 이해를 돕기 위해 작성하는 글입니다. Security를 커스터마이징하여 사용하기 앞서 동작 원리를 이해하고 프로젝트에 적용하기 위해 정리를 합니다.
Spring Security는 웹 서비스에서 MVC 패턴 이전에 작동하는 `필터`로서 동작합니다. 필터란 클라이언트 요청이 서블릿으로 가기 전에 먼저 처리할 수 있도록 톰캣(WAS)에서 지원해주는 기능입니다. 그래서 설정도 톰캣의 설정파일인 `web.xml`에 하지만, 스프링 부트를 사용하는 환경이고, 최신 스프링 부트(2.7 버전 이상)에서는 컴포넌트 기반의 설정을 지향하므로 컴포넌트 기반의 설정법을 다루어볼 예정입니다.
이 글의 중심은 Spring Security가 어떻게 필터 역할을 하는지에 대해서 중점적으로 다루어보려고 합니다.
스프링 시큐리티의 동작!
- 톰캣(WAS)가 구동되면서 실행할 필터들의 정보를 수집.
- 필터의 가장 큰 역할은 사용자 요청을 검증하고 필요에 따라 데이터를 추가하거나 변조하는 것이라고 보면 됩니다. 톰캣은 기본적으로 encoding 필터를 가지며 UTF-8 타입으로 변경해줍니다.
- 스프링 시큐리티 인터셉터는 요청에 대해서 특정 권한이 없을 경우 로그인 URL로 변경하여 서블릿에게 전달해 줍니다. 실제 request 객체의 요청을 변경하는 과정을 통해서 애플리케이션이 원하는 방향으로 유도하는 것입니다.
- 톰캣(WAS)에서 필터 클래스의 객체 생성 후 doFilter() 메소드 호출
- 각 filter는 doFilter() 메소드를 가지고 있고 request,와 response, filterchain을 파라미터로 가지며 filter의 역할을 다하게 되면 다음 filter로 넘겨주는 역할을 합니다.
- `DelegatingFilterProxy`가 Security filter를 등록.
-
- 제가 이해한 바를 설명하자면 톰캣(WAS)는 필터를 가지고 있고 위 그림처럼 FilterChain을 통해(web.xml에 정의된) 일련의 필터링 과정을 거치게 됩니다.
- 이 때 Spring이 제공하는 `DelegatingFilterProxy`가 서블릿 컨테이너의 생명주기와 스프링의 컨테이너 즉 ApplicationContext와의 접점으로 존재하게 되는데,
- `DelegatingFilterProxy`는 우리가 Spring Security Config에 설정해두었던 filter 값들을 FilterChain에 탑재시키면서 클라이언트에서 서버로 접근해오는 요청들을 필터 처리할 수 있도록 설정해줍니다.
- 각 filter는 각자 본연의 로직을 처리하고 위에서 언급했던 filterChain.doFilter()를 통해 다음 filter 가 있는지 식별하고 마지막 filter라면 서블릿으로 요청을 전달하여 최종적으로 MVC로 보내게 됩니다. `DelegatingFilterProxy`의 역할 - 스프링 Security에 정의한 filter들을 filter chain에 올려줌.
- spring.io 공식 문서
-
- FilterChain에 등록되는 Security Filter는 정해진 순서대로 동작.
- 다음은 공식 문서에 제공되는 표준 filter와 작동되는 순서입니다.
- 공식 문서
- 필터 클래스는 각 모듈 별 기능을 가진 객체(클래스)의 메소드를 호출해서 로직을 전개
- 아직 디테일하게 이해하지는 못했지만 각 필터의 로직이 전개되면서 구현체에서 필요한 로직을 가져다가 사용한다는 뜻 같습니다.
- 예를들어 RememberMeService 구현체에는 autoLogin(), loginFail(), loginSuccess(), logout() 등의 메소드들이 있지만 이 메소드 들을 호출하는 필터는 다 다르다는 이야기 입니다.
- 각각 autoLogin(), loginFail() 는 RememberMeAuthenticationFilter가 자동 로그인 기능과 권한 등록 과정에서 예외 발생시 사용하고, loginSuccess()는 UsernamePasswordAuthenticationFilter가 리멤버-미를 체크하고 로그인 했을 경우 쿠키 발행 및 등록을 처리할 경우 사용하고, logout() 은 LogoutFilter가 로그아웃시 쿠키 및 DB정보를 삭제할 때 사용하게 됩니다.
추가로 공식 문서에는 `after`와 `before`라는 속성으로 filter 사이에 insert 할 수 있다고 합니다.
이를 통해서 커스터마이징한 필터의 순서를 정할 수 있습니다. 다음 코드는 UsernamePasswordAuthenticationFilter 가 동작전에 filter를 위치시키는 코드입니다.
http
.addFilterBefore(formLoginFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
'Web Dev > Spring' 카테고리의 다른 글
[JPA] 도메인 설계 정리 (0) | 2023.03.14 |
---|---|
[Spring] 스프링 빈 충돌 이슈 관리 (0) | 2023.03.12 |
Spring - Paging 처리 (0) | 2022.08.22 |
IoC, DI, 컨테이너 그리고 Bean (0) | 2022.07.29 |
스프링 시작시 코드를 실행 시키는 3가지 방법 (0) | 2022.07.22 |