摘要:?jiǎn)栴}如何將新的發(fā)給前端比較好這個(gè)問(wèn)題答案簡(jiǎn)單,在的中設(shè)置。我這里使用解決的,將舊作為鍵,新作為值,設(shè)置一個(gè)秒過(guò)期的時(shí)間。大家可以享用這個(gè)新版,可以很好解決這個(gè)問(wèn)題。
前后端分離,使用token的方式校驗(yàn)用戶(hù)信息,我選擇了jwt,使用的教程在網(wǎng)上可以找到很多,不做介紹。
這里說(shuō)明一個(gè)使用過(guò)程中,最重要的的一個(gè)環(huán)節(jié)刷新token帶來(lái)的問(wèn)題。
業(yè)務(wù)要達(dá)到的目標(biāo):
用戶(hù)登錄一次之后,前端保存token,后面每次向后端請(qǐng)求的時(shí)候,header都帶上authorization信息,后端從請(qǐng)求中解析token,根據(jù)token驗(yàn)證用戶(hù)信息,返回相應(yīng)的信息。
相信大部分看過(guò)文檔并開(kāi)始使用的同學(xué)都已經(jīng)走通到這里了,下面是入坑的開(kāi)始:
1. 產(chǎn)品要求
半個(gè)月內(nèi)免登陸,這里就要使用到了refreshToken了,jwt設(shè)計(jì)思想很到位:設(shè)置發(fā)給前端的token一個(gè)有效期,比如2個(gè)小時(shí),2個(gè)小時(shí)候前端發(fā)來(lái)的token就會(huì)失效,這個(gè)時(shí)候我們根據(jù)發(fā)來(lái)的token判斷下,如果這個(gè)token在2個(gè)小時(shí)外,并在刷新token的有效期內(nèi)(比如半個(gè)月內(nèi)),那么我們?cè)诮o前端返回?cái)?shù)據(jù)的時(shí)候返回一個(gè)新token,前端接到這個(gè)token存儲(chǔ)起來(lái),當(dāng)再次請(qǐng)求的時(shí)候,發(fā)送新的token,如此周而復(fù)始,只要你在半個(gè)月內(nèi)沒(méi)有間斷去進(jìn)入系統(tǒng),那么完全不需要去進(jìn)行登錄的操作。
2. 問(wèn)題
1)如何將新的token發(fā)給前端比較好?
這個(gè)問(wèn)題答案簡(jiǎn)單,在response 的header中設(shè)置authorization。 關(guān)鍵點(diǎn):后端一般使用的域名是二級(jí)域名比如我的是api.xx.com,會(huì)和前端產(chǎn)生一個(gè)跨域的影響,請(qǐng)記得一定要設(shè)置 `$response->headers->set("Access-Control-Expose-Headers", "Authorization");` 設(shè)置跨域的時(shí)候還要設(shè)置一個(gè)Cache-Control,這個(gè)東西出現(xiàn)的問(wèn)題真的是莫名其妙,坑了我很久.. `$response->headers->set("Cache-Control", "no-store"); // 無(wú)的話(huà)會(huì)導(dǎo)致前端從緩存獲取頭token`
2) 一般是在中間件中刷新token,當(dāng)前請(qǐng)求繼續(xù)走,如何在controller中需要根據(jù)token調(diào)取登錄用戶(hù)信息?
一下子可能沒(méi)說(shuō)明問(wèn)題,簡(jiǎn)單理解為:token已經(jīng)刷新了,那么當(dāng)前token肯定失效了,繼續(xù)在controller利用請(qǐng)求中的token肯定會(huì)報(bào)token失效的錯(cuò)誤,這里需要將新token帶到后面的程序處理中,我這里更改了當(dāng)前請(qǐng)求頭,將newToken替換了request header中的Authorization。
3) 并發(fā)請(qǐng)求。也就是2個(gè)小時(shí)候之后,同一個(gè)頁(yè)面發(fā)來(lái)了2個(gè)請(qǐng)求,這個(gè)很正常,比如一個(gè)請(qǐng)求列表數(shù)據(jù),一個(gè)請(qǐng)求搜索的表單,因?yàn)閠oken都已失效,那么難道返回2個(gè)新的token回去?
這個(gè)問(wèn)題找了在github里面看到了issue但是無(wú)人回答,jwt肯定不會(huì)發(fā)兩個(gè)新的token回去的,那麼肯定會(huì)有一個(gè)token不僅是失效了,刷新當(dāng)前token之后,產(chǎn)生新的token,舊token加入到了backlist中了,無(wú)法使用,那么另外一個(gè)請(qǐng)求自然無(wú)法成功。我這里使用Redis解決的,將舊token作為鍵,新token作為值,設(shè)置一個(gè)30秒過(guò)期的時(shí)間。當(dāng)?shù)诙€(gè)請(qǐng)求來(lái)的時(shí)候,已經(jīng)知道token在backlist中了,我們可以去redis查詢(xún)下是否存在這么個(gè)舊token,存在的話(huà)放行。
3. 關(guān)鍵中間件代碼
setRequest($request)->getToken()) { return response()->json([ "code" => "2", "msg" => "無(wú)參數(shù)token", "data" => "", ]); } try { $user = $auth->authenticate($token); if (! $user) { return response()->json([ "code" => "2", "msg" => "未查詢(xún)到該用戶(hù)信息", "data" => "", ]); } $request->headers->set("Authorization","Bearer ".$token); } catch (TokenExpiredException $e) { try { sleep(rand(1,5)/100); $newToken = JWTAuth::refresh($token); $request->headers->set("Authorization","Bearer ".$newToken); // 給當(dāng)前的請(qǐng)求設(shè)置性的token,以備在本次請(qǐng)求中需要調(diào)用用戶(hù)信息 // 將舊token存儲(chǔ)在redis中,30秒內(nèi)再次請(qǐng)求是有效的 Redis::setex("token_blacklist:".$token,30,$newToken); } catch (JWTException $e) { // 在黑名單的有效期,放行 if($newToken = Redis::get("token_blacklist:".$token)){ $request->headers->set("Authorization","Bearer ".$newToken); // 給當(dāng)前的請(qǐng)求設(shè)置性的token,以備在本次請(qǐng)求中需要調(diào)用用戶(hù)信息 return $next($request); } // 過(guò)期用戶(hù) return response()->json([ "code" => "2", "msg" => "賬號(hào)信息過(guò)期了,請(qǐng)重新登錄", ]); } } catch (JWTException $e) { return response()->json([ "code" => "2", "msg" => "無(wú)效token", "data" => "", ]); } $response = $next($request); if ($newToken) { $response->headers->set("Authorization", "Bearer ".$newToken); } return $response; } }
一整天的時(shí)間耗在這里了,實(shí)踐才會(huì)發(fā)現(xiàn)問(wèn)題,累并快樂(lè)著解決了^_^
=====================割了一了白了(2019)===================
關(guān)于第三個(gè)問(wèn)題,當(dāng)時(shí)寫(xiě)的時(shí)候就感覺(jué)很惡心,作者已經(jīng)出了一個(gè)新版本(1.0.0-rc.1),config里面多了一項(xiàng)配置
"blacklist_grace_period" => env("JWT_BLACKLIST_GRACE_PERIOD", 60)
當(dāng)多個(gè)并發(fā)請(qǐng)求使用相同的JWT進(jìn)行時(shí),由于 access_token 的刷新 ,其中一些可能會(huì)失敗,以秒為單位設(shè)置請(qǐng)求時(shí)間以防止并發(fā)的請(qǐng)求失敗。
大家可以享用這個(gè)新版,可以很好解決這個(gè)問(wèn)題。中間件更新了部分:
try { // 刷新token,超時(shí)刷新將會(huì)去catch $refresh = JWTAuth::parseToken()->refresh(); $user = $auth->authenticate($refresh); // 生成新token(上面的$refresh也是合法的刷新token,這里如果直接用,2次刷新之后再無(wú)法繼續(xù)獲得,親測(cè)) $newToken = JWTAuth::fromUser($user); // 給當(dāng)前的請(qǐng)求設(shè)置性的token,以備在本次請(qǐng)求中需要調(diào)用用戶(hù)信息 $request->headers->set("Authorization","Bearer ".$newToken); }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/28232.html
摘要:在使用非對(duì)稱(chēng)加密算法進(jìn)行簽名的時(shí)候,還可以用于驗(yàn)證的發(fā)件人是否與中申明的發(fā)件人是同一個(gè)人。如果沒(méi)有用非對(duì)稱(chēng)加密算法的話(huà),把復(fù)制之后直接可以去官網(wǎng)在線(xiàn)解析。 這篇博客主要是簡(jiǎn)單介紹了一下什么是JWT,以及如何在Spring Boot項(xiàng)目中使用JWT(JSON Web Token)。 1.關(guān)于JWT 1.1 什么是JWT 老生常談的開(kāi)頭,我們要用這樣一種工具,首先得知道以下幾個(gè)問(wèn)題。 這...
摘要:設(shè)置過(guò)期時(shí)間每次登錄,包括登錄都返回一個(gè)可用的給客戶(hù)端,保證合理登錄的用戶(hù)都可以用,實(shí)現(xiàn)不會(huì)過(guò)期的效果。直接將中該用戶(hù)的信息過(guò)期。下次通過(guò)登錄,會(huì)提醒失效,要重新登錄,我們重新生成一個(gè)新的給用戶(hù),然后。。通過(guò)存儲(chǔ),實(shí)現(xiàn)過(guò)期失效的問(wèn)題了。 JWT 使用場(chǎng)景:(自己總結(jié)的,每次請(qǐng)求攜帶token,然后到服務(wù)端驗(yàn)證token是否正確,是否過(guò)期,然后解碼出攜帶的用戶(hù)信息。服務(wù)端不需要再存儲(chǔ)se...
摘要:簽發(fā)的用戶(hù)認(rèn)證超時(shí)刷新策略這個(gè)模塊分離至項(xiàng)目權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺(jué)那樣太長(zhǎng)了找不到重點(diǎn),分離出來(lái)要好點(diǎn)。這樣在有效期過(guò)后的時(shí)間段內(nèi)可以申請(qǐng)刷新。 簽發(fā)的用戶(hù)認(rèn)證token超時(shí)刷新策略 這個(gè)模塊分離至項(xiàng)目api權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺(jué)那樣太長(zhǎng)了找不到重點(diǎn),分離出來(lái)要好點(diǎn)。 對(duì)于登錄的用戶(hù)簽發(fā)其對(duì)應(yīng)的jwt,我們?cè)趈wt設(shè)置他的固定有效期時(shí)間,在有效期內(nèi)用戶(hù)攜帶jw...
閱讀 2988·2021-10-27 14:19
閱讀 603·2021-10-18 13:29
閱讀 1206·2021-07-29 13:56
閱讀 3616·2019-08-30 13:19
閱讀 2009·2019-08-29 12:50
閱讀 1173·2019-08-23 18:16
閱讀 3577·2019-08-22 15:37
閱讀 1952·2019-08-22 15:37