-
場景
第三方平臺需要內(nèi)嵌我們的管理頁面芭碍,但又不想單獨(dú)登陸我們的系統(tǒng)暴心,因此由我們通過一個(gè)默認(rèn)的賬號密碼進(jìn)行靜默登陸并重定向到第三方需要嵌入的頁面姐浮,這樣就可以通過后臺將接口調(diào)用憑證放入cookie中(我們的接口憑證信息放在cookie中珠增,請求時(shí)校驗(yàn))超歌。
-
問題
實(shí)際開發(fā)中發(fā)現(xiàn)在chrome瀏覽器下實(shí)現(xiàn)存在重定向后的頁面無法獲取cookie的情況。
-
實(shí)現(xiàn)過程
流程如下:
1.創(chuàng)建兩個(gè)項(xiàng)目蒂教,分別作為我們的平臺(project A) 和 第三方平臺 (project B)巍举。
2.project A 只放一個(gè)index.html頁面,內(nèi)部通過iframe嵌套project B的頁面凝垛。
樣例:<iframe src="http://localhost:8081/third/logon/login?param=eyJhY2NvdW50IjoiYWRtaW4iLCJwYXNzd29yZCI6InF3ZTEyMyIsInJvbGVDZCI6InN5c3RlbSIsInNvdXJjZSI6IjEifQ==" style="width: 100%;height: 1000px"> </iframe>
這是一個(gè)重定向的接口地址懊悯,參數(shù)為加密后的信息。
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 設(shè)置 cookie炭分, ResponseCookie cookie = ResponseCookie.from("tk", result.getJSONObject("properties").getString("accessToken")) // key & value .httpOnly(true) // 禁止js讀取 .path("/") // path .maxAge(3600 * 24 * 30) // 1個(gè)小時(shí)候過期 .build() ; // 設(shè)置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); } }
這里主要是設(shè)置cookie和response.sendRedirect。其他業(yè)務(wù)代碼可以忽略剑肯。
理論上我在project A的接口里設(shè)置cookie那么同域名下的前端頁面也是適用捧毛。事實(shí)如何呢?
前面我說目前已知Chrome(版本號:90.0.4430.93)無效让网。
實(shí)際開發(fā)中根據(jù)因?yàn)闉g覽器或版本不同呀忧,可能結(jié)果都不一樣。重定向接口返回:
從返回的圖片上可以看到溃睹,response header中嘗試去設(shè)置了cookie信息而账。這里說一下圖上 sameSite屬性是我為了測試主動設(shè)置。一般情況下是不會顯示的丸凭,瀏覽器默認(rèn)samesite的屬性為Lax福扬。感興趣的可以自己去了解一下腕铸。
傳送門:cookie的sameSite屬性
細(xì)心的可以看到set-cookie的最后有一個(gè)“警告”標(biāo)識。標(biāo)識的內(nèi)容為:
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被阻止铛碑,因?yàn)樗哂小?SameSite = Lax”屬性狠裹,但來自跨站點(diǎn)響應(yīng),而不是對頂級導(dǎo)航的響應(yīng)
簡單的來說就是出現(xiàn)了跨域請求汽烦,但瀏覽器默認(rèn)的SameSite=Lax是不支持跨域下cookie操作的涛菠。因此設(shè)置cookie失敗。具體原因可以參考上面的傳送門撇吞。
同域名下的展示頁請求信息:
重定向到的頁面俗冻,請求頭內(nèi)容的確沒有cookie信息,因此在頁面內(nèi)的請求也是無法正常請求的牍颈。
按這個(gè)思路迄薄,變更一下后端代碼中的cookie設(shè)置。
ResponseCookie cookie = ResponseCookie.from("tk", result.getJSONObject("properties").getString("accessToken")) // key & value
.httpOnly(true) // 禁止js讀取
.path("/") // path
.maxAge(3600 * 24 * 30) // 1個(gè)小時(shí)候過期
.sameSite("None")
.secure(true)
.build()
;
設(shè)置sameSite和secure煮岁。
sameSite設(shè)置為None讥蔽,Cookie將在所有上下文中發(fā)送,即允許跨域發(fā)送画机。
且必須要配合secure屬性使用冶伞,需要設(shè)置為true,僅支持https。
處理后再看一下重定向后的展示頁request header:
已經(jīng)存在了cookie信息步氏。問題解決响禽。
當(dāng)然并非這一種方式。通過設(shè)置瀏覽器也可以達(dá)到相同的效果荚醒。不過這里就不考慮了芋类,畢竟不可能要求用戶設(shè)置一下。