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