美文网首页
PHP实现JWT的token登录

PHP实现JWT的token登录

作者: Ben大师 | 来源:发表于2019-08-05 21:53 被阅读0次

    下面是完整的类的代码,使用也非常的简单,一个是getToken(),另一个是verifyToken()

    class Jwt
    {
        //这个是头部
        private static $header=array(
            'alg' => 'HS256',//生成signature的算法
            'typ' => 'JWT'//类型
        );
    
        //使用HMAC生成信息摘要时所使用的秘钥
        private static $key = '123456';
    
        /**
         * 获取jwt token
         * @param array $payload jwt荷载
         * @return bool|string
         */
        public static function getToken(array $payload){
            if(is_array($payload)){
                $base64header = self::base64UrlEncode(json_encode(self::$header,JSON_UNESCAPED_UNICODE));
                $base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
                $base64signature = self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']);
                return $token = $base64header . '.' . $base64payload . '.' . $base64signature;
            }else{
                return false;
            }
        }
    
        /**
         * 验证token是否有效,默认值验证exp时间
         * @param string $token 需要验证的token
         * @return bool|mixed 如果正确,那么,将返回数组$payload
         */
        public static function verifyToken(string $token){
            $tokens = explode('.', $token);
            if (count($tokens) != 3){
                return false;
            }
            list($base64header, $base64payload, $sign) = $tokens;
    
            //获取header部分
            $base64decodeheader = json_decode(self::base64UrlDecode($base64header),true);
            if (empty($base64decodeheader['alg'])){
                return false;
            }
    
            //签名验证,就是将现成的$base64header和$base64payload重新加密一遍,看是不是等于$sing
            $calc_sign = self::signature(
                $base64header . '.' . $base64payload,
                self::$key,
                $base64decodeheader['alg'],
                );
            if ($calc_sign != $sign){
                return false;
            }
    
            //获得payload
            $payload = json_decode(self::base64UrlDecode($base64payload),true);
    
            //核对过期时间是不是小于现在的时间,如果是,那就返回false
            if (isset($payload['exp']) && $payload['exp'] < time()){
                return false;
            }
    
            return $payload;
        }
    
        /**
         * 首先用base64_encode编码,然后换掉+/=这3个符号
         * 为什么不直接用urlEncode?
         * 我觉得可能是为了减少运算吧,反正就这3个符号,没有更多。
         * @param string $input 需要编码的字符串
         * @return string 编码后的字符串
         */
        private static function base64UrlEncode(string $input){
            return str_replace('=','',strtr(base64_encode($input),'+/','-_'));
        }
    
        /**
         * 解码由base64UrlEncode()编码的字符串
         * @param string $input
         * @return bool|string 解码后的字符串
         */
        private static function base64UrlDecode(string $input){
            $remainder = strlen($input) % 4;
            if ($remainder) {
                $addlen = 4 - $remainder;
                $input .= str_repeat('=', $addlen); //差了几个=就补上几个等号
            }
            return base64_decode(strtr($input, '-_', '+/'));
        }
    
        /**
         * HMACSHA256签名
         * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
         * @param string $key 秘钥
         * @param string $alg 算法
         * @return string 返回签名的编码后的字符串
         */
        private static function signature(string $input, string $key, string $alg = 'HS256'){
            $alg_config = array(
                'HS256' => 'sha256'
            );
            $signature = hash_hmac($alg_config[$alg], $input, $key, true);
            return self::base64UrlEncode($signature);
        }
    }
    

    贴上我在ThinkPHP中的测试代码:

    public function testToken(){
        $payload = [
            'exp' => time() + 9000,
            'name' => 'user',
            'jti' => '11111233'
        ];
        return $token = Jwt::getToken($payload);
    }
    
    public function testToken2(){
        $token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjUwMTk2NzIsIm5hbWUiOiLmsZ_niofniociLCJqdGkiOiIxMTExMTIzMyJ9.mgSMwnpHQiIlBYNGTphAsYWc2pTiygj1AhmQU_p1OBw';
        $payload = Jwt::verifyToken($token);
        dump($payload);
    }
    

    上面的代码是基于这个代码修改的(其实没有改多少,只是改了一些说明):https://www.jb51.net/article/146790.htm

    相关文章

      网友评论

          本文标题:PHP实现JWT的token登录

          本文链接:https://www.haomeiwen.com/subject/eawvdctx.html