简介

一:JWT介绍:全称JSON Web Token,基于JSON的开放标准((RFC 7519) ,以token的方式代替传统的Cookie-Session模式,用于各服务器、客户端传递信息签名验证。

二:JWT优点:

1:服务端不需要保存传统会话信息,没有跨域传输问题,减小服务器开销。

2:jwt构成简单,占用很少的字节,便于传输。

3:json格式通用,不同语言之间都可以使用。

三:JWT组成

1:jwt由三部分组成:

     头部(header)
     载荷(payload) 包含一些定义信息和自定义信息
     签证(signature)

2:具体构成:

header:


{
  "typ": "JWT", //声明类型为jwt
  "alg": "HS256" //声明签名算法为SHA256
}
载荷(payload)


{
  "iss": "http://www.helloweba.net",
  "aud": "http://www.helloweba.net",
  "iat": 1525317601,
  "nbf": 1525318201,
  "exp": 1525318201,
  "data": {
    "userid": 1,
    "username": "李小龙"
  }
}
载荷包括两部分:标准声明和其他声明。

标准声明:JWT标准规定的声明,但不是必须填写的;

标准声明字段:

接收该JWT的一方

iss: jwt签发者

sub: jwt所面向的用户

aud: 接收jwt的一方

exp: jwt的过期时间,过期时间必须要大于签发时间

nbf: 定义在什么时间之前,某个时间点后才能访问

iat: jwt的签发时间

jti: jwt的唯一身份标识,主要用来作为一次性token。


下载
composer require firebase/php-jwt

extend 下创建token类

namespace Token;

use think\Controller;
use think\facade\Request;
use Firebase\JWT\JWT;

/**token类
 * Class Token
 * @package app\api\Controller
 */
class Token
{

    /**
     * 创建 token
     * @param array $data 必填 自定义参数数组
     * @param integer $exp_time 必填 token过期时间 单位:秒 例子:7200=2小时
     * @param string $scopes 选填 token标识,请求接口的token
     * @return string
     */
    private $TokenKey = "123456";

    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=$this->TokenKey;
            $time = time(); //当前时间
            //$token['iss']=''; //签发者 可选
            //$token['aud']=''; //接收该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; //自定义参数
            }

            $json = JWT::encode($token,$key);

            $returndata['status']="200";//
            $returndata['msg']='success';
            $returndata['token']= $json;//返回的数据
            return $returndata; //返回信息


        }catch(\Firebase\JWT\ExpiredException $e){  //签名不正确
            $returndata['status']="104";//101=签名不正确
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            return $returndata; //返回信息
        }catch(\Exception $e) {  //其他错误
            $returndata['status']="199";//199=签名不正确
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            return $returndata; //返回信息
        }
    }

    /**
     * 验证token是否有效,默认验证exp,nbf,iat时间
     * @param string $jwt 需要验证的token
     * @return string $msg 返回消息
     */
    public function checkToken($jwt){
        $key=$this->TokenKey;

        try {
            JWT::$leeway = 60;//当前时间减去60,把时间留点余地
            $decoded = JWT::decode($jwt, $key, ['HS256']); //HS256方式,这里要和签发的时候对应
            $arr = (array)$decoded;


            $returndata['status']="200";//200=成功
            $returndata['msg']="success";//
            $returndata['data']=$arr;//返回的数据
            return $returndata; //返回信息

        } catch(\Firebase\JWT\SignatureInvalidException $e) {  //签名不正确

            $returndata['status']="101";//101=签名不正确
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            //return json_encode($returndata); //返回信息
            //exit(json_encode($returndata));
            sendResponse($returndata,401,'Unauthorized');
        }catch(\Firebase\JWT\BeforeValidException $e) {  // 签名在某个时间点之后才能用
            $returndata['status']="102";
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            sendResponse($returndata,401,'Unauthorized');
        }catch(\Firebase\JWT\ExpiredException $e) {  // token过期
            $returndata['status']="103";//103=签名不正确
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            sendResponse($returndata,401,'Unauthorized');
        }catch(\Exception $e) {  //其他错误
            $returndata['status']="199";//199=签名不正确
            $returndata['msg']=$e->getMessage();
            $returndata['data']="";//返回的数据
            sendResponse($returndata,401,'Unauthorized');
        }
        //Firebase定义了多个 throw new,我们可以捕获多个catch来定义问题,catch加入自己的业务,比如token过期可以用当前Token刷新一个新Token
    }
 签发
$jwtToken = new Token();
        $tokenData = array(
            'openid' => $user->getId(),
            'uniacid' => $_W['uniacid'],
        );
        $token = $jwtToken->createToken($tokenData)
验证
if (empty($_SERVER['HTTP_AUTHORIZATION']))
        {
            $res['status']="201";
            $res['msg']="no token";
            $res['data']="";//返回的数据
            sendResponse($res,401,'Unauthorized');
        }
        $token = $_SERVER['HTTP_AUTHORIZATION'];
        $jwtToken = new Token();
        $checkToken = $jwtToken->checkToken($token);
        $data = (array)$checkToken['data']['data'];