Keycloak Jakarta Servlet Filter Adapter 在认证失败响应中未设置CORS头的问题
先把你的问题场景再明确下:
我的Jakarta Web应用用了
keycloak-jakarta-servlet-filter-adapter对接Keycloak做认证。当用户认证通过且拥有要求的受众(audience)时,预检请求和实际请求的响应都能正确设置CORS头;但如果用户已经认证,却没有对应的受众权限,预检响应的CORS头是正常的,可返回403状态码的实际响应里却没有CORS头,导致前端跨域报错。
我之前碰到过类似的情况,给你几个可行的解决思路:
调整Keycloak适配器的CORS配置,覆盖错误场景的头设置
先检查你的Keycloak配置文件(比如keycloak.json或者Spring Boot项目里的application.properties/yaml),确保已经明确开启并配置CORS参数:
比如在keycloak.json里可以这么写:{ "cors": true, "allowedOrigins": ["https://你的前端实际域名"], "allowedMethods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"], "allowedHeaders": ["Authorization", "Content-Type"] }有些旧版本的适配器默认只会在请求成功处理后添加CORS头,明确配置这些参数后,大概率能让适配器在返回403这类错误响应时,也自动带上CORS头。
自定义一个优先级更高的CORS过滤器
如果适配器本身的逻辑有缺陷,那我们可以自己写一个Jakarta Servlet过滤器,把它放在Keycloak过滤器的前面执行——这样不管请求最后是成功还是返回错误,这个过滤器都能先给响应加上CORS头。
给你个简单的过滤器示例:@WebFilter(urlPatterns = "/*") @Order(Ordered.HIGHEST_PRECEDENCE) public class CustomCorsFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; // 替换成你的前端域名,或者动态获取请求头里的Origin httpResponse.setHeader("Access-Control-Allow-Origin", "https://你的前端实际域名"); httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); httpResponse.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); // 处理预检请求直接返回200 if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) { httpResponse.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(request, response); } }重点是要让这个过滤器的优先级比Keycloak的过滤器高,比如用
@Order(Ordered.HIGHEST_PRECEDENCE)标记,确保它先执行,把CORS头提前加上。升级Keycloak适配器版本
这个问题有可能是适配器的版本bug导致的——比如某些旧版的Jakarta适配器在处理授权失败(比如受众不匹配)的场景时,没有走CORS头的添加逻辑。你可以尝试把keycloak-jakarta-servlet-filter-adapter升级到最新的稳定版,看看官方有没有修复这个小问题。
备注:内容来源于stack exchange,提问作者Calcimicium

