Spring Security过滤器中后续请求的Cookie传递问题解决
我们的应用使用两个域名:example.com(公开域名)和my.example.com(仅面向已登录用户)。当用户从example.com发起需要认证的REST请求时,会触发Spring Security过滤器重定向到my.example.com,但重定向后的请求丢失了认证Cookie,导致403错误。
问题根源
- Cookie Domain限制:若认证Cookie的Domain仅设置为
example.com,浏览器会限制该Cookie只能在example.com域名下发送,不会携带到子域my.example.com的请求中。 - CORS配置冲突:当前代码同时设置
Access-Control-Allow-Origin: *和Access-Control-Allow-Credentials: true,这是浏览器禁止的组合——允许携带凭证时,Origin不能用通配符*,必须指定具体域名。 - 重定向未主动传递Cookie:重定向响应中未将原请求的Cookie重新绑定到目标域名,导致浏览器跳转后无法获取认证凭证。
解决方案
1. 修正认证Cookie的Domain设置
在生成认证Cookie(如Spring Security的JSESSIONID或自定义认证Cookie)时,将Domain设置为.example.com,让两个域名共享该Cookie:
Cookie authCookie = new Cookie("AUTH_TOKEN", tokenValue); authCookie.setDomain(".example.com"); // 前缀点表示覆盖主域及所有子域 authCookie.setPath("/"); authCookie.setHttpOnly(true); // 安全配置,防止XSS攻击 authCookie.setSecure(true); // 生产环境建议开启,仅通过HTTPS传输 response.addCookie(authCookie);
2. 修复CORS配置冲突
修改addCorsHeaders方法,动态获取请求Origin并指定允许的域名,同时确保允许携带凭证:
private void addCorsHeaders(HttpServletRequest request, HttpServletResponse response) { String origin = request.getHeader("Origin"); // 白名单校验,仅允许指定域名 if (origin != null && (origin.contains("example.com"))) { response.setHeader("Access-Control-Allow-Origin", origin); } response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Cookie"); // 明确允许携带Cookie头 response.setHeader("Access-Control-Allow-Credentials", "true"); }
调用该方法时需传入HttpServletRequest以获取请求Origin。
3. 重定向时主动复制Cookie
在过滤器的重定向分支中,将原请求的Cookie重新设置到响应中,绑定到目标域名:
else { String redirectUrl = getUrlToRedirect(myUrl, httpServletRequest); // 传入request修复CORS头 addCorsHeaders(httpServletRequest, httpServletResponse); // 复制原请求的Cookie到响应,设置正确Domain Cookie[] cookies = httpServletRequest.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue()); newCookie.setDomain(".example.com"); // 或直接指定"my.example.com" newCookie.setPath("/"); newCookie.setHttpOnly(cookie.isHttpOnly()); newCookie.setSecure(cookie.isSecure()); httpServletResponse.addCookie(newCookie); } } httpServletResponse.setHeader("Location", redirectUrl); httpServletResponse.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); }
额外注意事项
- 检查浏览器第三方Cookie设置:部分浏览器默认阻止第三方Cookie,需提示用户将
example.com和my.example.com加入例外列表。 - 生产环境强制HTTPS:配合Cookie的
Secure属性,确保Cookie仅通过安全通道传输,避免被拦截窃取。
内容的提问来源于stack exchange,提问作者Joe D
相关产品推荐
相关产品推荐

