CORS настройка spring security или игнор фильтра для одного адреса
Вот что получается: сервер принимает jwt токен аунтефикации, и, если токен присутствует в заголовке, он в любом случае сначала проверяет токен, и только потом пускает к ресурсам, даже общедоступным. И, если токен просрочен или невалиден, то сервер бросает ошибку аунтефикации и клиенту возвращается 401:
@RequiredArgsConstructor
public class JwtTokenFilter extends GenericFilterBean {
private final JwtTokenProvider jwtTokenProvider;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String token = jwtTokenProvider.retrieveAccessToken((HttpServletRequest) servletRequest);
try {
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
} catch (JwtAuthenticationException ex) {
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
httpServletResponse.sendError(HttpStatus.UNAUTHORIZED.value(), ex.getMessage());
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
=========================
@RequiredArgsConstructor
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final JwtTokenProvider provider;
@Override
public void configure(HttpSecurity builder) throws Exception {
JwtTokenFilter filter = new JwtTokenFilter(provider);
builder.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
}
Это решалось переопределением метода WebSecurityConfigurerAdapter:
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/publuc_urls");
}
Отлично, но, при попытке получить ресурсы со стороннего сайта (в моем случае клиента который делает ajax-запросы) - выпадает ошибка
Хотя, обращаю внимание, для адресов, которые не игнорятня в конфиге выше, все работает отлично, посколько CorsFilter присутствует. Вот конфиг:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.addFilterBefore(new CorsFilter(corsConfigurationSource()), SessionManagementFilter.class)
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello", "/login", "/register", "/refresh_token").permitAll()
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(provider));
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config.applyPermitDefaultValues());
return source;
}
То есть, если этот адрес игнорится, то он пролетает не только мимо jwt-фильтра, но и сors-фильтра.
Появилась необхоимость реализации рефреш-токена (клиент отправляет на сервер и просроченный токен доступа, и рефреш-токен). Мимо токен-фильтра он не может пройти поскольку токен доступа в заголовке просрочен, а мимо cors-фильтра не может пройти, поскольку запрос с левого сайта делается.
Что можно с этим сделать?
Ответы (1 шт):
web.ignoring()
Игнорирует все фильтры (SessionManagementFilter, CorsFilter, UsernamePasswordAuthenticationFilter и т.д.)
Но и сделать исключение каких-то url для фильтра JwtTokenFilter тоже нельзя, нет такого инструмента.
Но их можно и нужно написать самому:
private List<String> excludePatches = new ArrayList<>();
private AntPathMatcher antPathMatcher = new AntPathMatcher();
excludePatches.add("/recovery");
excludePatches.add("/js/**");
и добавить в фильтр токенов:
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
if(excludePatches.stream().anyMatch(p -> antPathMatcher.match(p, httpServletRequest.getServletPath()))) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
Настройки для cors и порядок фильтров:
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOriginPatterns(Collections.singletonList("*"));
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
http.addFilterBefore(new TokenFilter(tokenService), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new CorsFilter(source), TokenFilter.class);
