[Spring Security] AuthenticationProvider, OncePerRequestFilter
🔹 🚀 개념 정리
AuthenticationProvider | OncePerRequestFilter | |
언제 사용? | 주로 세션(Session) 기반 인증 | JWT 토큰 기반 인증 |
역할 | 로그인 요청 시 ID/PW 검증 및 세션 생성 | 모든 요청에서 JWT 검증 및 인증 정보 저장 |
어디에서 실행? | AuthenticationManager가 호출할 때 실행 (/auth/login) | HTTP 요청이 들어올 때마다 실행 (필터 체인에서 실행) |
Security 설정 | http.authenticationProvider(customAuthenticationProvider) | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) |
Spring Security 기본 구현체 | DaoAuthenticationProvider | UsernamePasswordAuthenticationFilter |
로그인 이후 인증 방식 | 세션 (SecurityContextHolder에 저장됨) | JWT (SecurityContextHolder에 저장됨) |
✅ 정리: AuthenticationProvider vs OncePerRequestFilter
✔ AuthenticationProvider → 세션(Session) 기반 인증에 사용
✔ OncePerRequestFilter → JWT 기반 인증에 사용
🔹 🚀 최종 개념 정리
AuthenticationProvider | OncePerRequestFilter | |
언제 사용? | 세션(Session) 기반 인증 | JWT 토큰 기반 인증 |
역할 | 로그인 요청 시 ID/PW 검증 및 세션 생성 | 모든 요청에서 JWT 검증 및 인증 정보 저장 |
어디에서 실행? | AuthenticationManager가 호출할 때 실행 (/auth/login) | HTTP 요청이 들어올 때마다 실행 (필터 체인에서 실행) |
Security 설정 | http.authenticationProvider(customAuthenticationProvider) | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) |
Spring Security 기본 구현체 | DaoAuthenticationProvider | UsernamePasswordAuthenticationFilter |
로그인 이후 인증 방식 | 세션 (SecurityContextHolder에 저장됨) | JWT (SecurityContextHolder에 저장됨) |
🔹 1. 세션(Session) 기반 인증 (Spring Security 기본)
- 로그인 시 AuthenticationProvider가 AuthenticationManager를 통해 실행됨.
- 인증이 성공하면 세션을 생성하고 SecurityContextHolder에 사용자 정보 저장.
- 이후 요청에서는 세션 쿠키를 사용하여 인증 정보를 확인.
✅ 세션 기반 인증 설정 예제
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final CustomAuthenticationProvider customAuthenticationProvider;
public SecurityConfig(CustomAuthenticationProvider customAuthenticationProvider) {
this.customAuthenticationProvider = customAuthenticationProvider;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authenticationProvider(customAuthenticationProvider) // 세션 기반 인증
.formLogin()
.loginProcessingUrl("/auth/login") // 로그인 요청 URL
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/home", true)
.failureUrl("/auth/login?error=true")
.and()
.logout()
.logoutUrl("/auth/logout")
.logoutSuccessUrl("/auth/login")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); // 세션을 유지 (기본값)
return http.build();
}
}
✔ authenticationProvider(customAuthenticationProvider) 설정하여 세션 기반 인증 수행.
✔ SessionCreationPolicy.IF_REQUIRED → 필요할 때만 세션 생성 (기본값).
✔ 이후 요청에서는 세션을 사용하여 로그인 상태 유지.
🔹 2. JWT 기반 인증 (Stateless)
- JWT는 세션을 사용하지 않고 Stateless 방식으로 동작.
- 사용자가 로그인하면 JWT 토큰을 발급하고, 이후 요청마다 OncePerRequestFilter를 사용하여 인증 수행.
- 즉, 모든 요청에서 HTTP 헤더의 JWT를 검사하여 SecurityContextHolder에 사용자 정보 저장.
✅ JWT 기반 인증 설정 예제
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 세션 사용 안 함
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) // JWT 필터 등록
.authorizeHttpRequests()
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll();
return http.build();
}
}
✔ sessionCreationPolicy(SessionCreationPolicy.STATELESS) → 세션을 사용하지 않음.
✔ addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) → JWT 필터를 로그인 필터보다 먼저 실행.
✔ /api/** 요청마다 JWT를 검사하여 인증 정보 확인.
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 요청 헤더에서 JWT 토큰 가져오기
String token = jwtTokenProvider.resolveToken(request);
// 토큰이 유효한 경우, SecurityContext에 저장
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
// 다음 필터로 요청 전달
chain.doFilter(request, response);
}
}
✔ 요청마다 JWT 토큰을 검사하여 SecurityContextHolder에 사용자 정보 저장.
✔ SecurityContextHolder에 인증 정보를 저장하면 컨트롤러에서 @AuthenticationPrincipal을 통해 사용자 정보 조회 가능.
🚀 최종 정리
사용 방식 | AuthenticationProvider (세션 기반) | OncePerRequestFilter (JWT 기반) |
세션 사용 여부 | ✅ 세션 사용 (SessionCreationPolicy.IF_REQUIRED) | ❌ 세션 없음 (SessionCreationPolicy.STATELESS) |
어디에서 사용? | 로그인 요청 (POST /auth/login) | 모든 요청 (/api/**) |
어떻게 인증? | 로그인 시 세션을 생성하여 관리 | HTTP 헤더의 JWT 토큰을 확인하여 인증 |
필요한 설정 | http.authenticationProvider(customAuthenticationProvider) | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) |
로그인 후 인증 정보 저장 위치 | 세션 (HttpSession) | SecurityContextHolder에 직접 저장 |
사용 예제 | 일반적인 로그인/로그아웃 시스템 | REST API 기반 JWT 인증 시스템 |
🚀 결론
✔ 세션 기반 인증 → AuthenticationProvider 사용 (SecurityContextHolder에 세션 저장)
✔ JWT 기반 인증 → OncePerRequestFilter 사용 (모든 요청마다 SecurityContextHolder에 인증 정보 저장)
✔ Spring Security에서 SessionCreationPolicy.STATELESS로 설정하면 AuthenticationProvider 방식이 아닌 JWT 인증을 사용해야 함.
🎯 즉, AuthenticationProvider는 세션 관리 방식에서 사용하고, OncePerRequestFilter는 JWT 방식에서 사용한다고 이해하면 됨! 🚀