RestTemplate發(fā)送請求時Cookie的影響及注意事項說明
背景
一個基于 SpringCloud 的多服務項目中,服務間調(diào)用通過 Spring 的 RestTemplate 實現(xiàn),后臺模塊 A 有一個定期清理無效業(yè)務數(shù)據(jù)的任務,它調(diào)用 Web 服務 B 的 API 時,竟然一直出現(xiàn) Token 已過期問題。
技術背景
- Web 服務權限認證使用 Token ,登錄校驗成功后,刷新 Token 并調(diào)用 response.addCookie 返回給調(diào)用方——瀏覽器或者內(nèi)部服務。
- Web 服務的攔截器,它提取 Token 的順序是:請求參數(shù)、Cookie、Header,然后驗證 Token 的有效性。校驗通過,刷新 Token 到響應對象的 Cookie 中。
- Token 有效期限 30 分鐘。
- 后臺定時任務模塊 A 每小時調(diào)用一次模塊 B 的的 API 。
對于 Web 服務模塊 B 來說,請求來源有用戶瀏覽器和內(nèi)部服務 A ,Token 校驗通過后會刷新并設置響應對象的 Cookie 中,而 Cookie 又會在下次請求時發(fā)送給服務器。
各服務穩(wěn)定運行后,定時任務 A 調(diào)用服務 B 的 API,從來都沒有成功過。
后臺服務調(diào)用時 Cookie 失效問題
問題描述
后臺服務 A 在調(diào)用 B 的 某API 時,雖然會生成新 Token 信息并設置到頭域,但是除了應用啟動時成功調(diào)用了一次,其他周期的調(diào)用都出現(xiàn)了 Token 已過期問題。
問題分析
分析整個認證過程,發(fā)現(xiàn)在 Web 的攔截器中,如果檢測到了內(nèi)部服務調(diào)用,會刷新 Token 信息并返回給 RestTemplate 對象,而且攔截器提取 Token 的順序是:請求參數(shù)、Cookie、Header。
// 請求參數(shù) String token = request.getParameter("t"); // Cookie if (StringUtils.isEmpty(token)) { ? ? Cookie[] cs = request.getCookies(); ? ? if (cs != null) { ? ? ? ? for (Cookie c : cs) { ? ? ? ? ? ? if ("t".equals(c.getName())) { ? ? ? ? ? ? ? ? token = c.getValue(); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? } } ?//Header if (StringUtils.isEmpty(token)) { ? ? token = request.getHeader("t"); }
問題癥結(jié)
后臺模塊 A 一小時執(zhí)行一次,每次調(diào)用使用 Spring 托管的 RestTemplate 單例對象發(fā)送請求給 B 時,它包含了上次請求收到的 Cookie 信息。
雖然同時生成了 Token 的頭域信息,但是在 Web 端優(yōu)先校驗了 Cookie ,因此認證結(jié)果始終是無效 Token ,請求被拒絕。
啟示錄
我從互聯(lián)網(wǎng)上得到的最好的經(jīng)驗之一,就是永遠不要復制和粘貼不是自己編寫的代碼。
如果你一定要復制,那就照著它逐字輸入,逼著自己思考,這些代碼實際上是什么意思。
這是昨天看科技周刊印象深刻的一句話,本文的問題雖然不是復制粘貼導致的,但它別人的代碼、別人的思想,我沒有深刻分析過。
當我臨時救火被分派解決這個問題時,簡單看了下代碼分析如下:
- 后端服務設置 Token 到了頭域
- 而 Web 模塊只從 Cookie 和請求參數(shù)中獲取 Token ,沒有從 Header 中獲取
想當然地以為,只要加上從 Header 中獲取就好了,而且陰差陽錯的加在了 Cookie 獲取的后面,所以問題還是沒有解決。
反復加日志,打印各個信息的 Token ,發(fā)現(xiàn)解析時用的 Token 跟頭域不一樣, Token 失效時間也很規(guī)律,就是上次定時任務的調(diào)用時間。突然意識到了,Web 服務用的 Token 跟我想的不一樣,誰把 Token 給改了?
答案是 Cookie,RestTemplate 竟然在發(fā)送請求時把上次的 Cookie 給帶上了。30分鐘的有效期,下一輪定時任務執(zhí)行時,早就是失效了啊。
RestTemplate 注意事項
用 RestTemplate 進行服務調(diào)用時,最好清掉 Cookie 信息,
一來避免本文出現(xiàn)的情況;
二來,它作為Spring 托管的單例,如果訪問的是不同系統(tǒng)的 API ,勢必會出現(xiàn) Cookie 混淆、失效的問題!
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java Socket實現(xiàn)聊天室附1500行源代碼
Socket是應用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口。本篇文章手把手帶你通過Java Socket來實現(xiàn)自己的聊天室,大家可以在過程中查缺補漏,溫故而知新2021-10-10spring boot 配置freemarker及如何使用freemarker渲染頁面
springboot中自帶的頁面渲染工具為thymeleaf 還有freemarker這兩種模板引擎,本文重點給大家介紹spring boot 配置freemarker及如何使用freemarker渲染頁面,感興趣的朋友一起看看吧2023-10-10Spring集成MyBatis?及Aop分頁的實現(xiàn)代碼
這篇文章主要介紹了Spring集成MyBatis?及Aop分頁的實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04SpringBoot?整合ChatGPT?API項目實戰(zhàn)教程
這篇文章主要介紹了SpringBoot整合ChatGPT API項目實戰(zhàn)教程,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05spring使用validation參數(shù)及全局異常檢測方式
本文主要介紹了Java的數(shù)據(jù)校驗規(guī)范validation-api,包括其定義的注解和HibernateValidator的實現(xiàn),還介紹了spring-boot-starter-validation的使用,可以讓開發(fā)者在SpringBoot應用中簡化數(shù)據(jù)校驗的功能2025-02-02openEuler?搭建java開發(fā)環(huán)境的詳細過程
這篇文章主要介紹了openEuler?搭建java開發(fā)環(huán)境,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06