博客列表 >ThinkPHP引入JWT实战

ThinkPHP引入JWT实战

孤行的博客
孤行的博客原创
2019年04月20日 22:34:302155浏览

轮子的使用

require firebase/php-jwt


一些常见的坑

签名的颁发者最好是个域名,最***看官方案例

生成的token会很长,建议存储token的字段用 text 类型

加密的类型要和解密的类型一样,默认是HS256加密


丢案例

namespace app\api\controller\v1;

use app\common\exception\ParamException;
use app\common\model\JwtToken;
use app\common\model\User;
use Firebase\JWT\JWT;
use think\Collection;
use think\exception\HttpResponseException;
use think\facade\Request;
use think\Response;

class Token
{
    private $client_id;
    private $secret_key;
    private $token;

    public function __construct($client_id = null,$secret_key = null)
    {
        $data = Request::param();
        if($client_id != null || !empty($data['client_id']) )
        {
            $this->client_id =  $client_id OR $this->client_id = $data['client_id'] ;
        }else{
            throw new ParamException(['msg'=>'client_id is nodefined']);
        }

        if($secret_key != null || !empty($data['secret_key']))
        {
            $this->secret_key =  $secret_key OR $this->secret_key = $data['secret_key'];
        }
        if(!empty(Request::header('token')))
        {
            $this->token = Request::header('token');
        }

    }

    /**
     * 获取token
     * @return array
     */
    public function getToken($type = 'json',$force = false)
    {
            if(!isset($this->secret_key)){
                throw new ParamException(['msg'=>'secret_key is nodefined']);
            }
            $obj = (new JwtToken())->get(['uid'=>$this->client_id,'key'=>$this->secret_key]);
            if($obj)
            {
                $expA = $obj->getData('temp_token');
                $expB = time() > $obj->getData('expire_time');
            }else{
                throw new ParamException(['msg'=>'client_id OR secret_key Exception']);
            }


        if(!$expA) {
            $result = $this->TokenHandler('generate');
        }else if($expB){
            $result = $this->TokenHandler('update');
        }else if($expA && !$expB){
            if($force)
            {
                $result = $this->TokenHandler('update');
            }else{
                $result = ['temp_token'=>$expA, 'expire_time'=>$obj->getData('expire_time')];
            }
        }

        switch($type)
        {
            case 'json':
            $response = Response::create($result,'json');
            throw new HttpResponseException($response);
                break;

            case 'array':
              return $result;
                break;
        };

    }

    /**
     * 签发token
     * @return array
     */
    private function issueToken()
    {
        $key = $this->secret_key;
        $userData = (new User())->get(['id'=>$this->client_id]);
        $nowTime = time();
        $exp_time = $nowTime + 7200;
        $jwt = [
            'iss' => $_SERVER['HTTP_HOST'],
            'iat' => $nowTime,
            'nbf' => $nowTime + 10,
            'exp' => $exp_time,
            'data' => $userData->getData()
        ];
        $token = (new JWT())->encode($jwt, $key);
        $result = ['temp_token'=>$token, 'expire_time'=>$exp_time];
        return $result;
    }

    /**
     * 生成或更新token
     * @return array
     */
    private function TokenHandler($type)
    {
        $tokenInfo = $this->issueToken();
        $map = [
            'temp_token' => $tokenInfo['temp_token'],
            'expire_time' => $tokenInfo['expire_time']
        ];

        switch($type)
        {
            case 'generate':
                $map['create_time'] = time();
                break;
            case  'update':
                $map['update_time'] = time();
                break;
        };


        $result = (new JwtToken())->update($map,['uid'=>$this->client_id]);
        if($result)
        {
            return  $tokenInfo;
        }
    }

    /**
     * 验证token
     */
    public function checkToken()
    {
        try{
            $res = $this->getTokenContent('array');
            $TokenInID = $res['data']->id;
            if($this->client_id == $TokenInID)
            {
                return true;
            }else{
                throw new ParamException(['msg'=>'Token and Client_id Exception']);
            }

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

            throw new ParamException(['msg'=>$e->getMessage()]);

        }catch (\Firebase\JWT\BeforeValidException $e){ // 签名在某个时间点之后才能用

            throw new ParamException(['msg'=>$e->getMessage()]);

        }catch(\Firebase\JWT\ExpiredException $e) {  // token过期

            throw new ParamException(['msg'=>$e->getMessage()]);

        }catch(\Exception $e) {  //其他错误
            throw new ParamException(['msg'=>$e->getMessage()]);
        }
    }

    /**
     * 解包token
     * @param $token
     * @param $key
     * @return object
     */
    private function decryptToken($token,$key)
    {
        JWT::$leeway = 60;
        $result = (new JWT())->decode($token, $key, ['HS256']);
        return $result;
    }

    /**
     * 获取token的内容
     */
    public function getTokenContent($type)
    {
        $key = $this->keyToClientID($this->client_id);
        $result = $this->decryptToken($this->token,$key);
        switch($type)
        {
            case 'json':
                $res = Collection::make($result)->toArray();
                $response = Response::create($res,'json');
                throw new HttpResponseException($response);
              break;

            case 'array':
                $res = Collection::make($result)->toArray();
                return $res;
             break;
        }

    }

    /**
     * 根据通信id返回秘钥
     * @param $client_id
     * @return mixed
     * @throws ParamException
     */
    private function keyToClientID($client_id)
    {
        $res = (new JwtToken())->get(['uid'=>$client_id]);
        if($res)
        {
            return $res->getData('key');
        }else{
            throw new ParamException(['msg'=>'secret_key nodefiend']);
        }
    }


}



看效果



声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议
孤行2019-04-20 14:57:111楼
123