其實把流程捋清楚了也很簡單,題主說到了返回用戶的Token信息。在大多數情況下Token和Cookie的作用是一樣的,用來保存用戶的某一些狀態。Cookie一般由瀏覽器或者客戶端自動維護失效狀態,服務端也可以根據請求頭中的Cookie信息來判斷用的某一些狀態的合法性,例如登錄狀態。那么Token就不一樣了,它不是Http協議中定義的東西,所以客戶端和瀏覽器都沒有對它進行一個規范的實現,因此它由服務端軟件和客戶端軟件來根據自身需求來各自實現,一般服務端會采用標準化的JWT(JSON Web Token)。Token的好處也是顯而易見的,比如可以輕松跨域、解耦性更強、對移動端更加友好等……
了解原理
要想真正的搞懂題主的問題,一定要對Token的工作原理和完整的協作流程有一個清晰的認知,因此咱們先來大致了解一下Token的原理和工作流程。
服務端有一個管理Token的緩存類,我們暫且把它叫做TokenCache。說到緩存無非就是增加、刪除和查詢,再加上一些類似LRU的算法做優化,當客戶端登錄后服務端會根據當前用戶的屬性生成一個加密的Token,然后緩存到這個TokenCache中登錄token無效,當客戶端請求某個接口時,服務端首先會檢查客戶端是否攜帶了Token,然后檢查Token是否在TokenCache中以驗證有效期,最后根據算法解密Token做一些權限邏輯判斷。注:這只是一個籠統的過程,很多服務端語言不完全如是。
下面用幾個具有代表性的場景配合幾張圖來說明客戶端和服務端的協作流程。不用登錄就可以成功請求;也就是不管是否攜帶了Token,不管Token是否有效就可以正常請求,比如App首頁:
2. 需要登錄后才可以成功請求,但是用戶并沒有登錄時;沒有登錄時請求時服務端會返回類似401這樣的狀態碼登錄token無效,表示客戶端需要登錄后才能正常請求:
3. 當客戶端進行登錄操作時;當客戶端在第2步檢測到服務端返回無效登錄狀態時,先應該判斷用戶是否登錄過了,如果用戶沒有登錄客戶端應該跳轉到登錄頁面讓用戶登錄:
4. 需要登錄后才可以成功請求,并且用戶已經正常登錄后;這種場景下客戶端應該攜帶了Token,而且Token是有效的:
5. 當用戶登錄后,過長時間沒有請求任何接口,例如登錄App就從未打開過,此時服務端保存的Token可能已經失效了,服務端也會返回類似401這樣的狀態碼:
這種場景往往很難查錯,往往也是客戶端和服務端同學互相甩鍋的地方,這一點也是題主提出的問題,當Token失效后到底該怎么辦?
解決方案
到這一步我們該總結一下出現問題的兩個地方了,除了用戶正常點擊登錄按鈕去登錄外,有兩個地方需要客戶端程序自動處理需要登錄這個狀態。在上述第2步和第5步都會出現登錄失效的狀態。在此先給出一些比較常見的處理建議:當接口響應401時,客戶端應該先檢查用戶是否已經登錄過了。
如果用戶沒有登錄過,客戶端程序應該跳轉到登錄頁面讓用戶登錄后再操作。
如果用戶登錄過,客戶端程序應該自動替用戶登錄,然后再重新請求之前響應401的接口。
第2步很簡單,對于第3步就顯得有一點復雜了,其實也并不復雜,只是有一部分客戶端開發者遇到這個問題時會想,那么多接口請求,難道每一個接口我都需要這樣做嗎?其實客戶端只需要在上面幾張圖的HttpProcessor處插入一段業務即可,大概流程是這樣的:
根據上圖中的步驟,我們把插入業務這一段叫做業務攔截器,下面我用偽代碼做個示例。
1. 這是負責請求服務端的Http類:
2. 這是插入業務的核心,業務攔截器:
3. 這是處理失效時跳轉和其它一些通用業務的HttpManager封裝
4. 調用的時候也就很簡單了,釋放天性咯
總結
現在來總結一下題主的問題,當用戶登錄后應該加密后保存用戶帳號密碼,當請求接口時接受到Token失效狀態,此時應該檢查用戶是否登錄過,也就是檢查是否有保存用戶帳號密碼,如果沒有登錄過則直接跳轉登錄頁面讓用戶登錄,如果用戶登錄過則使用已經保存的帳號密碼嘗試登錄一次,登錄成功則重新請求之前返回登錄失效狀態的接口,如果登錄失敗則跳轉登錄頁面讓用戶登錄。其中沒有登錄過跳轉登錄頁面和攔截狀態后登錄失敗跳轉登錄頁面其實最終是一個步驟了,因為客戶端只是插入了一段業務而已。