spring security를 설정하던 중 정적자원이나, swagger관련된 resources들은 필터가 설정되지 않도록 할 필요가 있었다.
처음에 security config에 다음과 같이 설정했으나 적용되지 않았다.
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/",
"/api/u/v1/social-login",
"/api-docs",
"/api-docs/**",
"/swagger-ui/**",
"/api/u/v1/token",
"/error",
"/",
"/swagger-config",
"/swagger.yaml",
"/requestBodies/**",
"/swagger-*.yaml"
).permitAll()
.requestMatchers(
"/api/u/v1/user"
).hasAnyRole("USER", "MANAGER")
)
.csrf(csrf -> {
csrf.disable();
})
.cors(cors -> {
cors.disable();
})
.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class)
.logout(logout -> logout.logoutSuccessUrl("/").permitAll());
return http.build();
}
방법은 websecuritycustomizer를 통해서 ignore설정을 해주는 것
package com.project.bookforeast.common.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.project.bookforeast.common.security.filter.JwtAuthorizationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
JwtAuthorizationFilter jwtAuthorizationFilter;
@Autowired
public SecurityConfig(JwtAuthorizationFilter jwtAuthorizationFilter) {
this.jwtAuthorizationFilter = jwtAuthorizationFilter;
}
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/",
"/api/u/v1/social-login",
"/api-docs",
"/api-docs/**",
"/swagger-ui/**",
"/api/u/v1/token",
"/error",
"/",
"/swagger-config",
"/swagger.yaml",
"/requestBodies/**",
"/swagger-*.yaml"
).permitAll()
.requestMatchers(
"/api/u/v1/user"
).hasAnyRole("USER", "MANAGER")
)
.csrf(csrf -> {
csrf.disable();
})
.cors(cors -> {
cors.disable();
})
.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class)
.logout(logout -> logout.logoutSuccessUrl("/").permitAll());
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(
"/favicon.ico",
"/swagger-ui/**",
"/",
"/swagger-config",
"/swagger.yaml",
"/requestBodies/**",
"/swagger-*.yaml",
"/error"
);
}
}
이는 securityFilterchain과 websecuritycustomizer의 차이에서 나오는데 WebSecurityCustomizer에서는 리소스에 대해서 Spring security가 적용되지 않도록 한다. 반면 SecurityFilterchaing의 permitAll의 경우 인증 결과와 상관없이 무조건 통과시키는 역할을 한다.
이 인증정보와 상관없이 무조건 통과시킨다는 부분이 좀 재미있는데, permitAll을 할 때 처음에는 내가 설정한 filter도 안탈꺼라고 생각했다. (인증 하는 부분을 permitAll로 해두었고, 인증과 관련된 내용을 jwtAuthorizationFilter에 설정했기 때문이었다.)
하지만 permitAll과 상관없이 jwtAuthorizationFilter가 돌았고, "/api/u/v1/social-login"와 같이 accessToken을 가지지 않은 엔드포인트에 대해서 에러가 발생했다. 이를 해결하기 위한 방법은 또 필터에 다음과 같이 설정해 주는 것
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String[] excludePath = {
"/api-docs/json",
"/api-docs",
"/api/u/v1/social-login",
"/swagger-ui/",
"/swagger-config",
"/swagger.yaml",
"/requestBodies",
"/swagger-",
"/error"
};
String path = request.getRequestURI();
System.out.println(path);
System.out.println(Arrays.toString(excludePath));
boolean shouldNotFilter = Arrays.stream(excludePath).anyMatch(path::startsWith);
return shouldNotFilter;
}
excludedPath에 포함되어 있으면 true를 반환하고 해당 필터를 타지 않도록 설정했다.
시큐리티는 할수록 더 어렵다