摘抄一篇JWT

来自 --- 找不到了,如果有人发现来源,请发个链接。

手写一遍 ,加深 印象。

使用tp框架,JWT写成了一个 中间件。

原理是php把一堆数据加密生成token给前段,前段请求接口带着这个token,php 解析token进行 验证。

需要在public/.htaccess加一行
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

1. 加密解密

    /**
     * 加密
     * 将 +/ 替换成 -_
     * 将 = 删除
     */
    private function base64UrlEncode($input): string
    {
        return str_replace('=', '', strtr(base64_encode($input), ['+/' => '-_']));
    }

    /**
     * 解密
     * 关于 %4 百度一下 base64_encode
     */
    private function base64UrlDecode($input)
    {
        $remainder = strlen($input) % 4;
        if ($remainder) {
            $addlen = 4 - $remainder;
            $input .= str_repeat('=', $addlen);
        }
        return base64_decode(strtr($input, ['-_' => '+/']));
    }

2. 生成签名

    /**
     * HMACSHA256 签名
     */
    private function signature($input, $key, $alg = 'HS256')
    {
        $alg_config = [
            'HS256' => 'sha256'
        ];
        return $this->base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key, true));
    }

3. 生成token之前的一些配置

    // 定义头部
    private $header = [
        'alg' => 'HS256', // 生成signature的算法
        'typ' => 'JWT' // 类型
    ];

    // 统一时间
    private $time = 0;

    public function __construct()
    {
        $this->time = time();
    }

    // 需要加密的信息
    private $payload;

    // 过期时间
    private $ttl = 10;
    private $refreshTtl = 7200;

    // 使用HMAC生成信息摘要时所使用的秘钥
    private $key = '123456';

    // 是否开启黑名单,开启后再校验token的时候会检查黑名单
    private $openBlackList = false;

    // 设置加密信息
    private function setPayload(array $pay = [])
    {
        $this->payload = [
            'iss' => 'jwt_admin', // 该JWT的签发者
            'iat' => $this->time, // 签发时间
            'exp' => $this->time, // 过期时间
            'nbf' => $this->time, // 改时间之前不接受处理该token
            'jti' => md5(uniqid('JWT') . $this->time), // 该token的唯一标识
            'sub' => '1', // 面向的用户,比如用户id
        ];
        $this->payload = array_merge($this->payload, $pay);
    }

    // 设置过期时间
    public function setTtl(int $seconds)
    {
        if ($seconds > 0) {
            $this->ttl = $seconds;
        }
    }

4. 生成 token

    /**
     * 生成token
     */
    public function createToken(array $payload)
    {
        $this->setPayload($payload);

        if (is_array($this->payload)) {
            $base64header = $this->base64UrlEncode(json_encode($this->header, JSON_UNESCAPED_UNICODE));
            $base64payload = $this->base64UrlEncode(json_encode($this->payload, JSON_UNESCAPED_UNICODE));
            $signature = $this->signature($base64header . '.' . $base64payload, $this->key, $this->header['alg']);
            $token = $base64header . '.' . $base64payload . '.' . $signature;
            return $token;
        } else {
            return false;
        }
    }

5. 验证token

    /**
     * 验证token
     */
    public function verifyToken($token)
    {
        $token1 = explode(' ', $token);
        if (count($token1) !== 2) {
            return false;
        }
        $tokens = explode('.', $token1[1]);
        if (count($tokens) !== 3) {
            return false;
        }
//        dd($tokens);
        list($base64header, $base64payload, $sign) = array_map(function($v){ return trim($v);},$tokens);

        // 获取jwt算法
        $base64decodeheader = json_decode($this->base64UrlDecode($base64header), true);
        if (empty($base64decodeheader['alg'])) {
            return false;
        }

        // 签名验证
        if ($this->signature($base64header . '.' . $base64payload, $this->key, $base64decodeheader['alg']) !== $sign) {
            return false;
        }

        $payload = json_decode($this->base64UrlDecode($base64payload), true);

        // 判断黑名单 $payload['jti']
        if ($this->openBlackList) {
//            return true;
        }

        // 签发时间大于当前服务器时间验证失败
        if (isset($payload['iat']) && $payload['iat'] > $this->time) {
//            return false;
        }

        // 过期时间小于当前服务器时间验证失败
        if (isset($payload['exp']) && $payload['exp'] < $this->time) {
//            return false;
        }

        // 该nbf时间之前不接收处理该token
        if (isset($payload['nbf']) && $payload['nbf'] > $this->time) {
//            return false;
        }

        return $payload;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值