本篇文章給大家帶來了關于thinkphp的相關知識,其中主要介紹了使用jwt認證的問題,下面一起來看一下,希望對大家有幫助。

thinkphp6 使用jwt
客戶端使用用戶名和密碼請求登錄
服務端收到請求,驗證用戶名和密碼
驗證成功后,服務端會簽發一個token,再把這個token返回給客戶端
客戶端收到token后可以把它存儲起來,比如放到cookie中
客戶端每次向服務端請求資源時需要攜帶服務端簽發的token,可以在cookie或者header中攜帶
服務端收到請求,然后去驗證客戶端請求里面帶著的token,如果驗證成功,就向客戶端返回請求數據
安裝 jwt 擴展
composer require firebase/php-jwt
安裝之后在 vender 目錄下的 firebase 文件夾下

調用 JWT里面的 encode 和 decode方法進行生成token和驗證token
項目app 目錄下的 common.php全局文件使用的 ,做成了公共方法,由于我是多應用的,所以就寫在了api下面的common.php,大家可以根據自己需求適當調整

首先 引入 JWT ,然后寫兩個方法,生成驗簽和驗證token。
<?php
use \Firebase\JWT\JWT;
use Firebase\JWT\Key;
// 應用公共文件
/**
* 生成驗簽
* @param $uid 用戶id
* @return mixed
*/
function signToken($uid){
$key='abcdefg'; //自定義的一個隨機字串用戶于加密中常用的 鹽 salt
$token=array(
"iss"=>$key, //簽發者 可以為空
"aud"=>'', //面象的用戶,可以為空
"iat"=>time(), //簽發時間
"nbf"=>time(), //在什么時候jwt開始生效
"exp"=> time()+30, //token 過期時間
"data"=>[ //記錄的uid的信息
'uid'=>$uid,
]
);
$jwt = JWT::encode($token, $key, "HS256"); //生成了 token
return $jwt;
}
/**
* 驗證token
* @param $token
* @return array|int[]
*/
function checkToken($token){
$key='abcdefg'; //自定義的一個隨機字串用戶于加密中常用的 鹽 salt
$res['status'] = false;
try {
JWT::$leeway = 60;//當前時間減去60,把時間留點余地
$decoded = JWT::decode($token, new Key($key, 'HS256')); //HS256方式,這里要和簽發的時候對應
$arr = (array)$decoded;
$res['status'] = 200;
$res['data'] =(array)$arr['data'];
return $res;
} catch(\Firebase\JWT\SignatureInvalidException $e) { //簽名不正確
$res['info'] = "簽名不正確";
return $res;
}catch(\Firebase\JWT\BeforeValidException $e) { // 簽名在某個時間點之后才能用
$res['info'] = "token失效";
return $res;
}catch(\Firebase\JWT\ExpiredException $e) { // token過期
$res['info'] = "token過期";
return $res;
}catch(Exception $e) { //其他錯誤
$res['info'] = "未知錯誤";
return $res;
}
}使用jwt生成token
/**
* 使用jwt生成token字符串
*/
public function setJwtToken()
{
$uid = input('uid'); // 接收生成token字符串 如:123
$token = signToken($uid);
// 生成字符串: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhYmNkZWZnIiwiYXVkIjoiIiwiaWF0IjoxNjQxNDUwMTU0LCJuYmYiOjE2NDE0NTAxNTcsImV4cCI6MTY0MTQ1NzM1NCwiZGF0YSI6eyJ1aWQiOiIxMjMifX0.I_GAkMsOhtEpIPkizCuQA-b9H6ovSovWx0AwAYI-b0s
echo $token;die;
}
/**
* 使用jwt驗證token字符串
*/
public function checkJwtToken()
{
$token = input('token'); // 接收生成token字符串
$result = checkToken($token);
// Array ( [status] => 200 [data] => Array ( [uid] => 123 ) )
print_r($result);die;
}創建 user 控制器
<?php
declare (strict_types = 1);
namespace app\api\controller;
use think\facade\Db;
use think\Request;
class User{
public function login(Request $request)
{
if ($request->isPost()){
$username = $request->param('username','','trim');
$password = $request->param('password','','trim');
//查詢數據庫
$user = Db::name('user')->where('username',$username)->find();
if (!$user){
return json(['status' => 'fail','msg' => '用戶名不存在']);
}
if ($user['password']!==md5($password)){
return json(['status' => 'fail','msg' => '密碼錯誤']);
}
$getToken = $this->token($user);
return json(['status' => 'success','msg' => '登陸成功','token' => $getToken]);
}
}
public function token($user)
{
$uid = $user['username']; // 接收生成token字符串 如:123
$token = signToken($uid);
dd($token);
}
/**
* 驗證token
*/
public function chToken()
{
$token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhYmNkZWZnIiwiYXVkIjoiIiwiaWF0IjoxNjQ4MDkwMDkyLCJuYmYiOjE2NDgwOTAwOTIsImV4cCI6MTY0ODA5MDEyMiwiZGF0YSI6eyJ1aWQiOiJcdTVmMjBcdTRlMDlcdTk4Y2UifX0.oJFpNcZ6stMymOCbD-meX0IPEIYLYNcwKxhMItF2cMw';
$result = checkToken($token);
// Array ( [status] => 200 [data] => Array ( [uid] => 123 ) )
print_r($result);die;
}
}用戶登錄成功返回給前端token,前端將token存儲起來,在下次請求的時候頭部攜帶著這個token,后端接受token,在中間件中進行驗證
創建api中間件
<?php
declare (strict_types = 1);
namespace app\middleware;
class Api{
/**
* 處理請求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
//toke 合法性驗證
$header = $request->header();
//判讀請求頭里有沒有token
if(!isset($header['token'])){
return json(['code'=>440,'msg'=>'request must with token']);
}
$token = $header['token'];
try {
// token 合法
$token = checkToken($token);
}catch (\Exception $e){
return json(['code'=>440,'msg'=>'invalid token']);
}
return $next($request);
}
}最后,關于如何處理token過期的問題,有兩種解決辦法,第一種就是,將token的時間設置長一些,這樣token就不會過期,但是這樣就有一個弊端,一旦客戶端拿到了這個token就相當于有了密鑰,主動權也就掌握在了用戶的手上。所以不推薦這種方案。第二種就是,后端處理,當token過期的時候重新獲取token,將新的token傳給前端,前端在將新的token存儲起來,替換掉原來的token,下一次請求的時候就攜帶著新的token請求。






