@Configuration
@EnableWebSecurity //스프링 시큐리티 필터(SecurityConfig)가 스프링 필터체인에 등록됨.
public class SecurityConfig {
// 스프링 부트 2.7.0 이상부턴 WebSecurityConfigurerAdapter가 deprecated됨.
// 아예 자체적으로 SecurityFilterChain Bean을 생성하는 방식으로 바뀌었다.
@Bean
public BCryptPasswordEncoder encodePwd(){
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션을 stateless로 관리
.httpBasic(AbstractHttpConfigurer::disable) // 기본적인 로그인 기능 사용 x
.formLogin(AbstractHttpConfigurer::disable)
// 특정 URL에 대한 권한 설정.
.authorizeHttpRequests((authorizeRequests) -> {
authorizeRequests.requestMatchers("/api/v1/user/**").hasAnyRole("ADMIN", "MANAGER","USER");
authorizeRequests.requestMatchers("/api/v1/manager/**")
.hasAnyRole("ADMIN", "MANAGER");
authorizeRequests.requestMatchers("/api/v1/admin/**")
.hasRole("ADMIN");
authorizeRequests.anyRequest().permitAll();
})
.build();
}
}
클라이언트 서버 방식은 원래 stateless기 때문에 상태를 가지지 않음.
하지만 세션이나 쿠키를 통해 stateful처럼 사용할 수 있다.
httpBasic(AbstractHttpConfigurer::disable)은 해당 방식을 사용하지 않겠다는 것이다.
form 방식의 로그인을 하지 않겠다는 것을 의미한다.
@CrossOrigin 어노테이션은 인증이 필요한 부분에서는 동작하지 않음.
따라서 필터를 만들고 등록해서 cors 설정을 해줘야함.
filterChain에 추가
.cors((cors)->{
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("*")); // 모든 ip에 응답을 허용
config.setAllowedHeaders(List.of("*")); // 모든 header에 대해 응답을 허용
config.setAllowedMethods(List.of("*"));// 모든 http method에 대해 허용
config.setAllowCredentials(true);// 내 서버가 응답을 할 때 json을 자바스크립트에서 처리할 수 있게 할지 설정
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**",config);
cors.configurationSource(source);
})
필터 생성
public class MYFilter1 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("filter 1");
chain.doFilter(request,response);
}
}
filterChain에 필터 등록
.addFilterBefore(new MYFilter1(),BasicAuthenticationFilter.class)
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MYFilter1> filter1(){
FilterRegistrationBean<MYFilter1> bean = new FilterRegistrationBean<>(new MYFilter1());
bean.addUrlPatterns("/*");
bean.setOrder(0); // 낮은 번호가 우선순위가 높음
return bean;
}
@Bean
public FilterRegistrationBean<MYFilter2> filter2(){
FilterRegistrationBean<MYFilter2> bean = new FilterRegistrationBean<>(new MYFilter2());
bean.addUrlPatterns("/*");
bean.setOrder(1);
return bean;
}
}

우선순위대로 나오는 것을 확인할 수 있다.
FilterChain에 필터3를 걸어보자

FilterChain이 먼저 나오는 것을 확인할 수 있다.
즉, SecurityFilter가 SpringFilter보다 먼저 실행된다.

만약 가장 먼저 실행되고 싶다면,가장 먼저 실행되는 필터인 SecurityContextPersistenceFilter에 걸면 된다.