当前位置: 移动技术网 > IT编程>开发语言>Java > Java单点登录 跨域时SameSite导致Cookie失败问题

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

2020年08月01日  | 移动技术网IT编程  | 我要评论
单点登录跨域碰上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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网