天天看點

tp5.1 建立簽名 驗證簽名 firebase php-jwt token

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值