欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java单点登录 跨域时SameSite导致Cookie失败问题

程序员文章站 2022-04-12 18:51:12
单点登录跨域碰上SameSite问题项目场景:问题描述:原因分析:解决方案:这里还遇到一个问题:headers一直是空?项目场景:两个项目:auth_webapp、admin_webapp单点登录流程:点击登录请求:/auth/api/login?name=xxx&password=xxx,auth服务器用jwt处理后获得token,将token写入cookie,并返回token。前端请求:/admin/api/getLoginVo,admin服务器返回提示未登录。前端再次请求:/au...



项目场景:

两个项目:auth_webapp、admin_webapp
单点登录流程:

  1. 点击登录请求:/auth/api/login?name=xxx&password=xxx,auth服务器用jwt处理后获得token,将token写入cookie,并返回token。
  2. 前端请求:/admin/api/getLoginVo,admin服务器返回提示未登录。
  3. 前端再次请求:/auth/api/login,此时不带用户名和密码,只是将1中的cookie带入request。
  4. 前端拿到3中的token请求:/admin/api/login?token=xxx,admin服务器验证token,返回登录结果。
  5. 前端再次请求:/admin/api/getLoginVo,admin服务器返回登录用户信息。

问题描述:

最近发现个别用户总是登录不了,通过分析请求发现,在流程3时,cookie没有写入request请求中,导致再次获取token失败,从而流程断裂。


原因分析:

百度SameSite可以知道是浏览器用来限制第三方cookie的,具体可以参考

http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html

正是由于Chrome更改了默认的SameSite属性,导致了在流程3时,不能将cookie写入request中。


解决方案:

既然明白了是SameSite属性导致了跨域cookie不能被使用,那么我们就将cookie的SameSite属性改成最低级的就可以解决这个问题了。在auth服务器中添加Interceptor:

public class SameSiteInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE); boolean firstHeader = true; for (String header : headers) { // there can be multiple Set-Cookie attributes response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=None; Secure;")); } } } 

这里还遇到一个问题:headers一直是空?

之前auth_webapp的容器使用的是undertow,headers一直获取不到,之后切换成了tomcat又可以了。

源码分析:
undertow的HttpServletResponse实现类是io.undertow.servlet.spec.HttpServletResponseImpl,源码分析:

public final class HttpServletResponseImpl implements HttpServletResponse { private final HttpServerExchange exchange; private final ServletContextImpl originalServletContext; private volatile ServletContextImpl servletContext; //此处省略无用代码 @Override public void addCookie(final Cookie cookie) { if (insideInclude) { return; } final ServletCookieAdaptor servletCookieAdaptor = new ServletCookieAdaptor(cookie); if (cookie.getVersion() == 0) { servletCookieAdaptor.setVersion(servletContext.getDeployment().getDeploymentInfo().getDefaultCookieVersion()); } exchange.setResponseCookie(servletCookieAdaptor); } } 

从源码可以看出,addCookie方法其实是将cookie保存在了exchange对象里面。而没有放入header中。对比而言,我们可以看看tomcat中的HttpServletResponse实现类org.apache.catalina.connector.ResponseFacade

 @Override public void addCookie(Cookie cookie) { if (isCommitted()) { return; } response.addCookie(cookie); } 

继续追org.apache.catalina.connector.Response.addCookie()

 /**
     * Add the specified Cookie to those that will be included with
     * this Response.
     *
     * @param cookie Cookie to be added
     */ @Override public void addCookie(final Cookie cookie) { // Ignore any call from an included servlet if (included || isCommitted()) { return; } cookies.add(cookie); String header = generateCookieString(cookie); //if we reached here, no exception, cookie is valid // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 ) // RFC2965 is not supported by browsers and the Servlet spec // asks for 2109. addHeader("Set-Cookie", header, getContext().getCookieProcessor().getCharset()); } 

本文地址:https://blog.csdn.net/y1378503395/article/details/108236630

相关标签: Java cookie jwt