-
场景
第三方平台需要内嵌我们的管理页面,但又不想单独登陆我们的系统,因此由我们通过一个默认的账号密码进行静默登陆并重定向到第三方需要嵌入的页面,这样就可以通过后台将接口调用凭证放入cookie中(我们的接口凭证信息放在cookie中,请求时校验)。
-
问题
实际开发中发现在chrome浏览器下实现存在重定向后的页面无法获取cookie的情况。
-
实现过程
流程如下:
1.创建两个项目,分别作为我们的平台(project A) 和 第三方平台 (project B)。
2.project A 只放一个index.html页面,内部通过iframe嵌套project B的页面。
样例:<iframe src="http://localhost:8081/third/logon/login?param=eyJhY2NvdW50IjoiYWRtaW4iLCJwYXNzd29yZCI6InF3ZTEyMyIsInJvbGVDZCI6InN5c3RlbSIsInNvdXJjZSI6IjEifQ==" style="width: 100%;height: 1000px"> </iframe>
这是一个重定向的接口地址,参数为加密后的信息。
3.通过projecet A接口重定向到projecet A的展示页。后端的代码部分:
public void login(ThirdLoginCrmLoginRequest request, HttpServletResponse response) throws Exception { //模拟登陆 JSONObject result = RestTemplateUtils.postForEntity(loginUrl, initLoginParam(request)); if (result.getInteger("code") == 200) { //response 设置 cookie, ResponseCookie cookie = ResponseCookie.from("tk", result.getJSONObject("properties").getString("accessToken")) // key & value .httpOnly(true) // 禁止js读取 .path("/") // path .maxAge(3600 * 24 * 30) // 1个小时候过期 .build() ; // 设置Cookie Header response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString()); ThirdLoginCrmEnum source = ThirdLoginCrmEnum.getWithSource(request.getSource()); //重定向的地址 response.sendRedirect(source == null ? ThirdLoginCrmEnum.ThirdRedirectCommon.domain: source.getRedirectUrl(request)); } else { response.sendRedirect(ThirdLoginCrmEnum.ThirdRedirectCommon.domain); } }
这里主要是设置cookie和response.sendRedirect。其他业务代码可以忽略。
理论上我在project A的接口里设置cookie那么同域名下的前端页面也是适用。事实如何呢?
前面我说目前已知Chrome(版本号:90.0.4430.93)无效。
实际开发中根据因为浏览器或版本不同,可能结果都不一样。重定向接口返回:
从返回的图片上可以看到,response header中尝试去设置了cookie信息。这里说一下图上 sameSite属性是我为了测试主动设置。一般情况下是不会显示的,浏览器默认samesite的属性为Lax。感兴趣的可以自己去了解一下。
传送门:cookie的sameSite属性
细心的可以看到set-cookie的最后有一个“警告”标识。标识的内容为:
This Set-Cookie was blocked because it had the "SameSite=Lax" attribute but come from a cross-site response which was not the response to a top-level navigation
此Set-Cookie被阻止,因为它具有“ SameSite = Lax”属性,但来自跨站点响应,而不是对顶级导航的响应
简单的来说就是出现了跨域请求,但浏览器默认的SameSite=Lax是不支持跨域下cookie操作的。因此设置cookie失败。具体原因可以参考上面的传送门。
同域名下的展示页请求信息:
重定向到的页面,请求头内容的确没有cookie信息,因此在页面内的请求也是无法正常请求的。
按这个思路,变更一下后端代码中的cookie设置。
ResponseCookie cookie = ResponseCookie.from("tk", result.getJSONObject("properties").getString("accessToken")) // key & value
.httpOnly(true) // 禁止js读取
.path("/") // path
.maxAge(3600 * 24 * 30) // 1个小时候过期
.sameSite("None")
.secure(true)
.build()
;
设置sameSite和secure。
sameSite设置为None,Cookie将在所有上下文中发送,即允许跨域发送。
且必须要配合secure属性使用,需要设置为true,仅支持https。
处理后再看一下重定向后的展示页request header:
已经存在了cookie信息。问题解决。
当然并非这一种方式。通过设置浏览器也可以达到相同的效果。不过这里就不考虑了,毕竟不可能要求用户设置一下。