Spring Security is a framework that provides authentication, authorization, and protection against common attacks. With first class support for securing both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications.
Spring Security는 인증, 인가, 그리고 일반적인 보안 공격에 대한 보호 기능을 제공하는 프레임워크입니다.
명령형(Imperative)과 반응형(Reactive) 애플리케이션 모두를 안정적으로 지원하며,
스프링 기반 애플리케이션 보안을 위한 사실상 표준(de-facto standard)으로 자리잡고 있습니다.
구분 | 설명 |
---|---|
명령형(Imperative) | 일반적인 방식의 프로그래밍으로, 요청이 들어오면 순차적으로 처리하고 응답을 반환함. Spring MVC 가 대표적 |
반응형(Reactive) | 비동기 & 논블로킹 방식으로, 이벤트 기반으로 데이터를 처리함. 리소스를 효율적으로 사용하며 대규모 트래픽에 유리. Spring WebFlux 가 대표적 |
Http Request가 DispatcherServlet으로 도달하기 전 Servlet의 Filter를 기반으로 Request에 대한 인증과 인가를 적용시켜주는 프레임워크이다.
HTTP 요청 → Tomcat → "Filter" → DispatcherServlet(FrontController)
→ Interceptor → Controller → Service → Repository
일반적으로 클라이언트에서 요청을 보내면, DispatcherServlet이 하나의 HttpServeletRequest를 받아서 요청을 처리하고 HttpServletResponse 응답을 클라이언트로 보낸다.
그런데, 하나 이상의 Filter가 포함된다면, 클라이언트에서 보낸 요청이 Servlet으로 전달되기 전에 Filter를 거치게 된다.
❓ Servlet(서블릿)
- 클라이언트의 요청을 처리하고, 그 결과를 반환하는 자바 웹프로그래밍 기술
- 작성한 자바파일이 컴파일되어 클래스파일로 변환
- 클래스파일을 톰캣(Servlet Container)에 등록
- 클라이언트의 요청이 들어오면, 서블릿 컨테이너가 알맞는 서블릿 메소드 실행
❓ Servlet Container (Tomcat)
- 웹서버(Apache)와의 통신을 처리
- Listen/Accept와 같은 통신 과정을 대신 해줌
- 서블릿(Servlet)의 생명주기를 관리
- 멀티스레딩 지원
코드를 직접 작성할 경우 스프링에서 추구하는 IoC/DI 패턴과 같은 확장 패턴을 염두해서 인증/인가 부분을 직접 개발하기는 쉽지 않은데, Spring Security에서는 이와 같은 기능들을 제공해 주기 때문에 개발 작업 효율을 높일 수 있기 때문에 사용한다고 한다.
스프링 시큐리티는 서블릿의 필터를 기반으로 동작한다.
필터는 말그대로 ‘필터’의 역할을 한다.
필터에서 요청을 걸러냈을 경우, 필터 내부에서 HttpServletResponse를 만들어 서블릿 대신 응답을 보낼 수 있다.
GET http://localhost:8080/mypage
요청이 있을 때,
이 접근은 인가(권한 체크)를 필요로 한다.
로그인 하지 않으면 볼 수 없어야 하기 떄문이다.
HTTP 요청이 우리 서버(Servlet)에 도착하기 전에 미리 수행해주는(걸러 주는) 역할을 하는 게 필터다.
✅ 서블릿컨테이너와 스프링컨테이너의 연결다리 역할이다.
HTTP 요청 → Tomcat → "Filter" → DispatcherServlet
→ Controller → Service → Repository
요청 흐름을 다시보자.
우리는 Controller
에 접근하기 전에 인증과 권한 작업을 수행해야 한다.
서블릿 컨테이너(톰캣)는 Servlet Filter를 직접 등록하지만,
Spring Bean으로 등록된 객체들(ex. JwtFilter)은 톰캣이 인식할 수 없다.
그래서 직접 만든 필터가 Spring Bean이면, 톰캣은 그걸 모른다.
따라서 스프링 시큐리티에서는 DelegatingFilterProxy라는 서블릿 필터의 구현체를 제공한다.
[DelegatingFilterProxy (서블릿 필터)]
↓
[FilterChainProxy (Spring Bean)]
↓
[SecurityFilterChain0] → 필터 A, 필터 B, 필터 C
[SecurityFilterChain1] → 필터 A, 필터 D ...
/api/** 요청 → [JWT 인증 필터, 권한 필터, CSRF 필터]
/login 요청 → [UsernamePasswordAuthenticationFilter, CSRF 필터]
✅ 즉, URL 패턴에 따라 다른 필터 묶음(=SecurityFilterChain) 을 적용할 수 있도록 도와주는 역할을 한다.
💡 Security Filter의 실행 순서는 SecurityFilterChain에서 정할 수 있다.
public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .addFilterBefore(new JwtFilter(jwtProvider), UsernamePasswordAuthenticationFilter.class) ...
CustomFilter(JwtFilter)를 UsernamePasswordAuthenticationFilter 앞에서 실행되게 하는 코드이다.
사용자 요청
↓
[서블릿 컨테이너] // 톰캣
↓
DelegatingFilterProxy // 서블릿 컨테이너 & 스프링 컨테이너 연결다리
↓
FilterChainProxy // 여러 SecurityFilterChain 관리 및 어떤걸 실행할지 결정
↓
SpringFilterChain // 특정 URL에 대해 적용할 필터들의 목록과 순서 보유
↓
Spring Security Filters // 실제 우리가 구현한 필터들 동작
↓
DispatcherServlet → Controller → Service → Repository
UsernamePasswordAuthenticationToken
생성AuthenticationProvider
→ UserDetailsService
→ User
객체 조회SecurityContextHolder
에 인증 정보 저장❓ JwtFilter(CustomFilter)를 쓴다면
Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, authorities); SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder
에 인증객체를 직접 넣어주면된다.
내배캠 튜터님들 및 특강자료
[스프링 공식문서] 스프링 시큐리티 6.4.5
[스프링 공식문서] 스프링 시큐리티 5.4.2
[이랜서 개발블로그] 스프링 시큐리티란?
스프링 시큐리티 동작과정에 대해 알아보자
스프링 시큐리티 구조와 동작원리
서블릿과 서블릿 컨테이너1
서블릿과 서블릿 컨테이너2