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 шт):

Автор решения: lampa
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);
→ Ссылка