1、安裝vendor擴充包firebase php-jwt token
2、設定版本
3、控制器代碼 測試網址:http://www.xxx.com/api/v1/index
<?php
namespace app\api\controller\v1;
use \Firebase\JWT\JWT; //導入JWT
class Index extends Common{
/**
* 頭部 公共參數
* @param array $header 頭部參數數組
* @param string $alg 聲明簽名算法為SHA256
* @return string $typ 聲明類型為jwt
*/
private static $header=array(
'alg'=>'HS256', //生成signature的算法 //聲明簽名算法為SHA256
'typ'=>'JWT' //聲明類型為jwt
);
/**
* 建立 token
* @param array $data 必填 自定義參數數組
* @param integer $exp_time 必填 token過期時間 機關:秒 例子:7200=2小時
* @param string $scopes 選填 token辨別,請求接口的token
* @return string
*/
public function createToken($data="",$exp_time=0,$scopes=""){
//JWT标準規定的聲明,但不是必須填寫的;
//iss: jwt簽發者
//sub: jwt所面向的使用者
//aud: 接收jwt的一方
//exp: jwt的過期時間,過期時間必須要大于簽發時間
//nbf: 定義在什麼時間之前,某個時間點後才能通路
//iat: jwt的簽發時間
//jti: jwt的唯一身份辨別,主要用來作為一次性token。
//公用資訊
try {
$key=TokenKey;
$time = time(); //目前時間
$token['iss']='http://www.fn321.com|Fneducms'; //簽發者 可選
$token['aud']='http://www.fn321.com|Fneducms'; //接收該JWT的一方,可選
$token['iat']=$time; //簽發時間
$token['nbf']=$time; //(Not Before):某個時間點後才能通路,比如設定time+30,表示目前時間30秒後才能使用
if($scopes){
$token['scopes']=$scopes; //token辨別,請求接口的token
}
if(!$exp_time){
$exp_time=7200;//預設=2小時過期
}
$token['exp']=$time+$exp_time; //token過期時間,這裡設定2個小時
if($data){
$token['data']=$data; //自定義參數
}
$token = [
'iss' => 'http://www.fn321.com|Fneducms', //簽發者 可選
'aud' => 'http://www.fn321.com|Fneducms', //接收該JWT的一方,可選
'iat' => $time, //簽發時間
'nbf' => $time, //(Not Before):某個時間點後才能通路,比如設定time+30,表示目前時間30秒後才能使用
'scopes' => $scopes, //token辨別,請求接口的token
'exp' => $time+$exp_time, //token過期時間,這裡設定2個小時
'params' => $data
];
$json = JWT::encode($token,$key);
//Header("HTTP/1.1 201 Created");
//return json_encode($json); //傳回給用戶端token資訊
return $json; //傳回給用戶端token資訊
}catch(\Firebase\JWT\ExpiredException $e){ //簽名不正确
$returndata['code']="104";//101=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}catch(Exception $e) { //其他錯誤
$returndata['code']="199";//199=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}
}
/**
* 驗證token是否有效,預設驗證exp,nbf,iat時間
* @param string $jwt 需要驗證的token
* @return string $msg 傳回消息
*/
public function checkToken($jwt){
$key=TokenKey;
//$jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuZm4zMjEuY29tfEZuZWR1Y21zIiwiYXVkIjoiaHR0cDpcL1wvd3d3LmZuMzIxLmNvbXxGbmVkdWNtcyIsImlhdCI6MTU0MTc1NDQ4MiwibmJmIjoxNTQxNzU0NDgyLCJzY29wZXMiOiJyb2xlX2FjY2VzcyIsImV4cCI6MTU0MTc2MTY4MiwiZGF0YSI6eyJ1c2VyaWQiOjIxLCJ1c2VybmFtZSI6Ilx1Njc0ZVx1NWMwZlx1OWY5OSJ9fQ.eSWijLKzIBpS--wPhtL7zUn-ConFA69-FdpfqfDVtpM";
try {
JWT::$leeway = 60;//目前時間減去60,把時間留點餘地
$decoded = JWT::decode($jwt, $key, ['HS256']); //HS256方式,這裡要和簽發的時候對應
$arr = (array)$decoded;
$returndata['code']="200";//200=成功
$returndata['msg']="成功";//
$returndata['data']=$arr;//傳回的資料
return json_encode($returndata); //傳回資訊
} catch(\Firebase\JWT\SignatureInvalidException $e) { //簽名不正确
//echo "2,";
//echo $e->getMessage();
$returndata['code']="101";//101=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}catch(\Firebase\JWT\BeforeValidException $e) { // 簽名在某個時間點之後才能用
//echo "3,";
//echo $e->getMessage();
$returndata['code']="102";//102=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}catch(\Firebase\JWT\ExpiredException $e) { // token過期
//echo "4,";
//echo $e->getMessage();
$returndata['code']="103";//103=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}catch(Exception $e) { //其他錯誤
//echo "5,";
//echo $e->getMessage();
$returndata['code']="199";//199=簽名不正确
$returndata['msg']=$e->getMessage();
$returndata['data']="";//傳回的資料
return json_encode($returndata); //傳回資訊
}
//Firebase定義了多個 throw new,我們可以捕獲多個catch來定義問題,catch加入自己的業務,比如token過期可以用目前Token重新整理一個新Token
}
/**
* 接口首頁 沒有内容
* @url /api/v1/index
* @method POST
*/
public function index(){
//url:http://www.cms.com/api/v1/index
//自定義資訊,不要定義敏感資訊
$data['userid']=21;//使用者ID
$data['username']="李10小龍";//使用者ID
$exp_time=7200; //token過期時間,這裡設定2個小時
$scopes='role_access'; //token辨別,請求接口的token
//生成簽名
$json = action('createToken',['data'=>$data,'exp_time'=>$exp_time,'scopes'=>$scopes]);
//echo $json."<br>"; //傳回給用戶端token資訊
//驗證簽名
$checkToken = action('checkToken',['jwt'=>$json]);
Header("HTTP/1.1 201 Created");
echo $checkToken; //傳回給用戶端token資訊
}
/**
* 擷取使用者登入資訊
* @url /api/v1.index/login
* @method POST
* @param integer $page 頁數
* @param integer $limit 每頁個數
* @return integer $code 狀态碼
* @return string $msg 傳回消息
*/
public function login(){
//登入思路:用戶端通過使用者名密碼登入以後,服務端傳回給用戶端兩個token:access_token和refresh_token。
//access_token:請求接口的token
//refresh_token:重新整理access_token
//舉個例子:比如access_token設定2個小時過期,refresh_token設定7天過期,2小時候後,access_token過期,但是refresh_token還在7天以内,那麼用戶端通過refresh_token來服務端重新整理,服務端重新生成一個access_token;
//如果refresh_token也超過了7天,那麼用戶端需要重新登入擷取access_token和refresh_token。
//為了區分兩個token,我們在載荷(payload)加一個字段 scopes :作用域。
//access_token中設定:scopes:role_access
//refresh_token中設定:scopes:role_refresh
//自定義資訊,不要定義敏感資訊
$data['userid']=21;//使用者ID
$data['username']="李小龍";//使用者ID
//請求接口的token
$exp_time1=7200; //token過期時間,這裡設定2個小時
$scopes1='role_access'; //token辨別,請求接口的token
$access_token = action('createToken',['data'=>$data,'exp_time'=>$exp_time1,'scopes'=>$scopes1]);
//重新整理refresh_token
$exp_time2=86400 * 30; //refresh_token過期時間,這裡設定30天
$scopes2='role_refresh'; //token辨別,重新整理access_token
$refresh_token = action('createToken',['data'=>$data,'exp_time'=>$exp_time2,'scopes'=>$scopes2]);
// //公用資訊
// $token = [
// 'iss' => 'http://www.helloweba.net', //簽發者 可選
// 'aud' => 'http://www.helloweba.net', //接收該JWT的一方,可選
// 'iat' => $time, //簽發時間
// 'nbf' => $time, //(Not Before):某個時間點後才能通路,比如設定time+30,表示目前時間30秒後才能使用
// 'data' => $data
// ];
// //請求接口的token 使用者名登入驗證通過時生成的
// $access_token = $token; // access_token
// $access_token['scopes'] = 'role_access'; //token辨別,請求接口的token
// $access_token['exp'] = $time+7200; //access_token過期時間,這裡設定2個小時
// //重新整理access_token
// $refresh_token = $token; //refresh_token
// $refresh_token['scopes'] = 'role_refresh'; //token辨別,重新整理access_token
// $refresh_token['exp'] = $time+(86400 * 30); //refresh_token過期時間,這裡設定30天
$jsonList = [
'access_token'=>$access_token,
'refresh_token'=>$refresh_token,
'token_type'=>'bearer' //token_type:表示令牌類型,該值大小寫不敏感,這裡用bearer
];
Header("HTTP/1.1 201 Created");
echo json_encode($jsonList); //傳回給用戶端token資訊
}
}
4、使用者登入接口 http://www.xxx.com/api/v1.index/login
注意:
$key常量放到公共檔案中:路徑:\application\common.php
define('Key', 'ffeyJ0eXAiOiJKV1QiLCJhbGciOi5');//API接口$key值