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

React-Python通过Spring Security对接Keycloak的CORS跨域问题

问题:React应用通过Spring Security对接Keycloak时的CORS拦截问题

架构背景

localhost:3000的React-Python应用调用localhost:80的Spring-Java认证服务,该服务已对接localhost:4000的Keycloak服务器。

测试情况

  1. 直接访问认证服务对接Keycloak - 验证成功:
    从localhost:80发起请求,能正常重定向到Keycloak认证页面,响应头和请求头均无异常。

  2. 通过React应用跳转时触发CORS错误:
    请求从http://localhost:3000/login重定向到http://localhost:80/oauth2/authorization/keycloak时,被浏览器CORS策略拦截,错误提示:No 'Access-Control-Allow-Origin' header is present on the requested resource。第一次重定向正常,第二次跳转触发该问题。

已配置代码

OAuth2配置

http.oauth2Login()
        .and()
        .exceptionHandling()
        // Specific entry point for failed authentication
        .authenticationEntryPoint(getEntryPoint())
        .and()
        .oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());

http.addFilterAfter(corsFilter(), SessionManagementFilter.class);
...

CORS Filter实现

public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request= (HttpServletRequest) servletRequest;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Max-Age", "180");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }
}

认证入口点配置

private AuthenticationEntryPoint getEntryPoint() {
    return (request, response, authException) -> {
        if (authException != null) {
            response.sendRedirect("/oauth2/authorization/keycloak");
        } else {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        }
    };
}

诉求

实现localhost:3000通过认证服务正常重定向到Keycloak完成认证,解决上述CORS问题。


解决方案

1. 调整CORS过滤器执行顺序

当前CORS过滤器添加在SessionManagementFilter之后,但Spring Security认证相关过滤器执行更早,导致重定向响应未被CORS处理就返回。需将CORS过滤器放在过滤器链最前端:

// 替换原addFilterAfter,改为前置添加
http.addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class);

2. 修复CORS配置冲突

Access-Control-Allow-Origin: *与Access-Control-Allow-Credentials: true不兼容,浏览器禁止这种组合。需指定具体允许的Origin:

// 替换通配符为React应用地址
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
// 多Origin场景可动态判断:
// String origin = request.getHeader("Origin");
// if (Arrays.asList("http://localhost:3000", "其他允许地址").contains(origin)) {
//     response.setHeader("Access-Control-Allow-Origin", origin);
// }

3. 优化前端跳转方式

避免通过AJAX请求触发认证跳转,直接通过浏览器顶级导航跳转:

// React中跳转示例
window.location.href = "http://localhost:80/oauth2/authorization/keycloak";

顶级导航不受CORS策略限制,能正常触发重定向流程。

4. 改用Spring Security内置CORS配置

替换自定义Filter,使用Spring Security原生CORS支持,更适配其过滤器链:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "DELETE"));
    config.setAllowedHeaders(Arrays.asList("*"));
    config.setAllowCredentials(true);
    config.setMaxAge(180L);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

// 在Security配置中启用
http.cors().configurationSource(corsConfigurationSource())
        .and()
        .oauth2Login()
        .and()
        .exceptionHandling()
        .authenticationEntryPoint(getEntryPoint())
        .and()
        .oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());

5. 配置Keycloak客户端允许跨域

登录Keycloak控制台,找到对应客户端,在Web Origins字段添加http://localhost:3000和http://localhost:80,避免后续回调环节触发CORS错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:10:25