Spring Security는 요청이 컨트롤러에 닿기 전에 서블릿 필터(servlet filter) 묶음에서 인증·인가를 처리한다. SecurityFilterChain 빈으로 어떤 경로를 열고 막을지 선언한다.
- 프런트 비유: Express 미들웨어 체인과 닮았다. 다만 필터 순서가 프레임워크에 정해져 있고, 내 필터는 기존 필터 앞뒤에 끼운다(
addFilterBefore) - 토큰 방식은 JWT 검증 필터를 끼우고, 세션 방식은 세션에 인증 정보를 둔다
- 인증(authentication) 실패(누구인지 모름)는 401, 인가(authorization) 실패(권한 없음)는 403이다
- CORS(Cross-Origin Resource Sharing) 처리도 필터 단계에서 일어나므로, Security를 붙인 뒤에는 preflight 요청을 따로 확인한다
설정 방식의 변화
예전에는 WebSecurityConfigurerAdapter를 상속해 설정했지만, 5.7에서 deprecated되고 6에서 제거됐다. 지금은 SecurityFilterChain 빈을 등록한다. 경로 지정도 antMatchers·mvcMatchers 대신 requestMatchers를 쓴다(2026 기준).
@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**", "/actuator/health").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.build();
}permitAll은 공개 경로,denyAll은 코드를 지우지 않고 막아 둘 때,authenticated는 로그인 필요- 패턴은 위에서부터 처음 맞는 규칙이 적용되므로 구체적인 경로를 먼저 쓴다
InMemoryUserDetailsManager나spring.security.user.*속성으로 만든 사용자는 PoC(Proof of Concept)용이다. 운영에서는 DB·LDAP(Lightweight Directory Access Protocol)·OAuth2 서버로 인증한다- 직접 인증 로직이 필요하면
AuthenticationProvider를 구현해authenticate·supports를 채운다. 비밀번호 비교는PasswordEncoder에 맡긴다(비밀번호 저장: 인코딩·암호화·해싱) - 상태를 바꾸는 요청에는 CSRF 보호가 기본으로 켜져 있다. 끌 때는 쿠키 인증을 쓰지 않는지 먼저 확인한다
- 필터에서 난 인증·인가 실패는 스프링 전역 예외 처리까지 가지 않는다.
AuthenticationEntryPoint·AccessDeniedHandler가 응답을 만든다(인증과 인가)
flowchart TD R[요청] --> F["필터 체인 (인증 · 인가)"] F -->|통과| C[컨트롤러] F -->|"인증 실패 → AuthenticationEntryPoint"| E[401] F -->|"인가 실패 → AccessDeniedHandler"| D[403]
출처: Spring Security 문서: SecurityFilterChain · Security Filters · Authorize HttpServletRequests