傳統互聯網項目在實現保持登錄狀態、退出登錄、接口請求等功能時會使用Session,但是眾所周知Session數據在產生后會存儲與服務器端,所以當用戶量達到一定程度會相應影響到服務器的性能,且Session在前后端分離的項目中或是多服務器項目中的支持不是很好。但是Token不會產生這些問題,服務器端對Token只有生成和驗證操作,不會存放數據,針對前后端分離的項目,包括手機APP和當前熱門的小程序的支持都很不錯,所以Token成為了用於驗證的極好選擇。
對Token有了一定了解后那么JWT又是什么呢?
JWT全稱為Json Web Token,是一種基於Token的身份認證方案,JWT的安全特性可以使Token不被修改和偽造。
那么接下來就具體說說JWT如何在ThinkPHP5.1框架中得到應用:
首先我們需要使用Composer來為我們的TP5.1項目安裝JWT。在TP5.1項目中使用命令行運行以下代碼即可自動下載安裝:
composer require firebase/php-jwt
運行后出現以下字樣並在框架vendor下可以找到firebase即代表下載安裝成功。
JWT成功集成到框架中后便可以使用了,這里再說明一下JWT生成的Token格式
首先我們可以進入JWT的官網,首頁有一個Debugger可以用於查看生成與驗證Token,除了官網我更推薦使用JWT的瀏覽器插件,不論哪種方法,最終使用效果都是一樣的,我這里使用JWT插件來演示,首先打開Debugger就可以看到官方生成用於展示的Token:
可以清楚看到整個Token分為三個部分,每個部分之間有一個 . 作為隔斷,首先紅色的部分為頭部(Header):說明此串碼為JWT和加密所用的算法信息,紫色的部分為負載(Payload):用於添加想要傳遞的信息和Token基本設置等,最后藍色的部分為驗證簽名(verify signature):用於密匙加密解密Token。知道了Token基本的格式后我們就可以開始使用TP5.1生成一個JWT看看效果了,為了方便演示,我將生成的函數放在了公共函數文件common.php中。
function createToken($adminId=666) { $secret = "THIS_IS_SECRET"; //密匙 $payload = [ 'iss'=>'sol', //簽發人(官方字段:非必需) 'exp'=>time()+3600*24*7, //過期時間(官方字段:非必需) 'aud'=>'admin', //受眾(官方字段:非必需) 'nbf'=>time(), //生效時間(官方字段:非必需) 'iat'=>time(), //簽發時間(官方字段:非必需) 'admin_id'=>$adminId, //自定義字段 'admin'=>true //自定義字段 ]; $token = JWT::encode($payload,$secret,'HS256'); return $token; }
代碼中使用JWT生成Token需要三個參數,分別是負載(Payload)、密匙(secret)、加密算法(algorithm),其中密匙是由自己規定的,之后接收到傳來的Token時需要使用此密匙來驗證接收到的Token,負載部分為想要傳輸的信息,其中有一些字段為官方定義的,但是並不是必需的,除此之外我們還可以定義一些自己的私有字段用來傳輸額外信息,例如以上實例中將簽發時間和生效時間設置為當前時間,Token過期時間為當前時間的七天后,並加上了自己定義的管理員ID字段和是否是管理員的字段。
定義好這些信息后就可以使用JWT的靜態方法encode來生成一個Token,這里我使用halt來獲取一下使用此函數生成的Token:
string(225) "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJpc3MiOiJzb2wiLCJleHAiOjE1NjU1OTYyNzYsImF1ZCI6ImFkbWluIiwibmJmIjoxNTY0OTkxNDc2LCJpYXQiOjE1NjQ5OTE0NzYsImFkbWluX2lkIjoiNjY2IiwiYWRtaW4iOnRydWV9.
jCVh-13ZOBEiIORdmw9Ye191X9ZJNyjo4fN96umG878"
然后就可以復制一下這段Token使用官方的Debugger來測試一下是否正確:
可以看到右側PAYLOAD里的信息和我們函數中定義的信息一致,但是下方顯示驗證失敗,這是因為Debugger自動生成的Secret並不正確,將黑框內的secret改為我們定義的密匙:THIS_IS_SECRET后便驗證成功了。
至此便成功的使用JWT生成可用的Token了,那么接下來就需要在框架中對接收到的Token進行驗證了
同樣在common.php中寫入驗證的函數:
function checkToken($token) { try{ $Result = JWT::decode($token,'THIS_IS_SECRET',['HS256']); return '驗證成功'; } catch (Exception $e) { return '驗證失敗'; } }
驗證Token需要的靜態方法decode同樣需要三個參數,第一個是需要驗證的Token,第二個是驗證的密匙,第三個是加密算法。
如果驗證成功則$Result的值為Token的負載(Payload)部分。如果驗證失敗的話則會拋出異常,所以Token驗證環節需要用try catch
,這里對異常捕捉沒有具體細分,不論是密匙錯誤還是Token過期還是其他錯誤統統都是驗證失敗,如果想將異常信息獲取的具體一點可以使用firebase中的三個異常信息來捕獲,請自己測試。
在具體業務中生成Token往往用於首次登錄或者修改密碼等信息后重登陸或者同賬號異地登陸頂號操作,在用戶進行操作時可以延長Token過期時間避免正在操作時突然提示Token過期重登陸破壞使用體驗。后台生成Token和其他信息一起返回前端后需要將Token信息保存在本地存儲或Cookie中,在下一次請求發送時將Token放在HTTP請求頭中一起發送,后台在接收到后先驗證Token是否正確可用在進行之后操作。
請求頭添加Token只需在Ajax請求中添加以下字段即可:
headers:{ token:'HTTP HEADER AJAX TOKEN TEST'}
- 1
在后台獲取只需使用Request靜態方法單獨獲取頭部token字段即可獲取Token內容並進行后續的驗證操作:
$token = Request::header('token');
- 1
需要JWT瀏覽器Debugger插件和JWT完整包的可以評論索取