You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理CORS后请求未进入@WebFilter引发401错误求解决方案

问题分析与解决方案

问题根因

你添加的WebSecurityConfig启用了Spring Security的过滤器链,它的优先级远高于普通的@WebFilter注解的过滤器。这导致你的自定义AuthorisationFilter完全没机会处理请求,所有请求都被Spring Security默认的httpBasic认证拦截,所以返回401未授权。

具体修复步骤

1. 调整自定义过滤器的注册方式

移除AuthorisationFilter上的@WebFilter注解,改成让Spring管理这个过滤器(比如加@Component),然后把它加入到Spring Security的过滤器链中。

2. 修改WebSecurityConfig配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    private final AuthorisationFilter authorisationFilter;

    // 构造注入自定义过滤器
    public WebSecurityConfig(AuthorisationFilter authorisationFilter) {
        this.authorisationFilter = authorisationFilter;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .cors(Customizer.withDefaults())
                .authorizeRequests(auth -> auth.anyRequest().authenticated())
                // 关闭不需要的httpBasic认证
                .httpBasic(httpBasic -> httpBasic.disable())
                // 将自定义过滤器添加到Security链中,位置根据你的认证逻辑调整,这里放在用户名密码过滤器之后
                .addFilterAfter(authorisationFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8081"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE", "OPTIONS"));
        // 补充常用请求头,比如Content-Type
        configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
        // 如果前端需要携带cookie,开启这个配置(前端也要对应设置withCredentials: true)
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

3. 确保自定义过滤器逻辑正确

检查你的AuthorisationFilter,确保它能正确解析Authorization头,并将认证信息存入SecurityContextHolder,示例逻辑如下:

@Component
public class AuthorisationFilter extends OncePerRequestFilter {

    // 替换成你实际的JWT工具类或认证逻辑依赖
    private final JwtTokenUtil jwtTokenUtil;

    public AuthorisationFilter(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            String username = jwtTokenUtil.extractUsername(token);
            
            // 仅当当前无认证信息时处理
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                // 根据实际情况构造认证对象,填充用户权限
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        username,
                        null,
                        Collections.emptyList()
                );
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        
        filterChain.doFilter(request, response);
    }
}

额外注意事项

  • OPTIONS预请求会被Spring Security自动处理,只要CORS配置正确就无需额外放行
  • 如果前端需要发送cookie,必须同时开启后端的setAllowCredentials(true)和前端请求的withCredentials: true

内容的提问来源于stack exchange,提问作者Bungle1981

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:55:22