php实现JWT(json web token)鉴权实例详解

吾爱主题 阅读:112 2021-09-16 15:37:00 评论:0

JWT是什么

JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。基于token的身份验证可以替代传统的cookie+session身份验证方法。

JWT由三个部分组成:header.payload.signature

以下示例以JWT官网为例

header部分:

?
1 2 3 4 {   "alg" : "HS256" ,   "typ" : "JWT" }

对应base64UrlEncode编码为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

说明:该字段为json格式。alg字段指定了生成signature的算法,默认值为 HS256,typ默认值为JWT

payload部分:

?
1 2 3 4 5 {   "sub" : "1234567890" ,   "name" : "John Doe" ,   "iat" : 1516239022 }

对应base64UrlEncode编码为:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

说明:该字段为json格式,表明用户身份的数据,可以自己自定义字段,很灵活。sub 面向的用户,name 姓名 ,iat 签发时间。例如可自定义示例如下:

?
1 2 3 4 5 6 7 8 {    "iss" : "admin" ,     //该JWT的签发者    "iat" : 1535967430,    //签发时间    "exp" : 1535974630,    //过期时间    "nbf" : 1535967430,     //该时间之前不接收处理该Token    "sub" : "www.admin.com" //面向的用户    "jti" : "9f10e796726e332cec401c569969e13e"  //该Token唯一标识 }

signature部分:

?
1 2 3 4 5 HMACSHA256(   base64UrlEncode(header) + "." +   base64UrlEncode(payload),   123456 )

对应的签名为:keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU

最终得到的JWT的Token为(header.payload.signature):eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU
说明:对header和payload进行base64UrlEncode编码后进行拼接。通过key(这里是123456)进行HS256算法签名。

JWT使用流程

  1. 初次登录:用户初次登录,输入用户名密码
  2. 密码验证:服务器从数据库取出用户名和密码进行验证
  3. 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
  4. 返还JWT:服务器的HTTP RESPONSE中将JWT返还
  5. 带JWT的请求:以后客户端发起请求,HTTP REQUEST
  6. HEADER中的Authorizatio字段都要有值,为JWT
  7. 服务器验证JWT

PHP如何实现JWT

作者使用的是PHP 7.0.31,不废话,直接上代码,新建jwt.php,复制粘贴如下:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 <?php /**   * PHP实现jwt   */ class Jwt {      //头部    private static $header = array (      'alg' => 'HS256' , //生成signature的算法      'typ' => 'JWT'  //类型    );      //使用HMAC生成信息摘要时所使用的密钥    private static $key = '123456' ;      /**     * 获取jwt token     * @param array $payload jwt载荷  格式如下非必须     * [     * 'iss'=>'jwt_admin', //该JWT的签发者     * 'iat'=>time(), //签发时间     * 'exp'=>time()+7200, //过期时间     * 'nbf'=>time()+60, //该时间之前不接收处理该Token     * 'sub'=>'www.admin.com', //面向的用户     * 'jti'=>md5(uniqid('JWT').time()) //该Token唯一标识     * ]     * @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));        $token = $base64header . '.' . $base64payload . '.' .self::signature( $base64header . '.' . $base64payload ,self:: $key ,self:: $header [ 'alg' ]);        return $token ;      } else {        return false;      }    }      /**     * 验证token是否有效,默认验证exp,nbf,iat时间     * @param string $Token 需要验证的token     * @return bool|string     */    public static function verifyToken(string $Token )    {      $tokens = explode ( '.' , $Token );      if ( count ( $tokens ) != 3)        return false;        list( $base64header , $base64payload , $sign ) = $tokens ;        //获取jwt算法      $base64decodeheader = json_decode(self::base64UrlDecode( $base64header ), JSON_OBJECT_AS_ARRAY);      if ( empty ( $base64decodeheader [ 'alg' ]))        return false;        //签名验证      if (self::signature( $base64header . '.' . $base64payload , self:: $key , $base64decodeheader [ 'alg' ]) !== $sign )        return false;        $payload = json_decode(self::base64UrlDecode( $base64payload ), JSON_OBJECT_AS_ARRAY);        //签发时间大于当前服务器时间验证失败      if (isset( $payload [ 'iat' ]) && $payload [ 'iat' ] > time())        return false;        //过期时间小宇当前服务器时间验证失败      if (isset( $payload [ 'exp' ]) && $payload [ 'exp' ] < time())        return false;        //该nbf时间之前不接收处理该Token      if (isset( $payload [ 'nbf' ]) && $payload [ 'nbf' ] > time())        return false;        return $payload ;    }      /**     * base64UrlEncode  https://jwt.io/ 中base64UrlEncode编码实现     * @param string $input 需要编码的字符串     * @return string     */    private static function base64UrlEncode(string $input )    {      return str_replace ( '=' , '' , strtr ( base64_encode ( $input ), '+/' , '-_' ));    }      /**     * base64UrlEncode https://jwt.io/ 中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签名  https://jwt.io/ 中HMACSHA256签名实现     * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)     * @param string $key     * @param string $alg  算法方式     * @return mixed     */    private static function signature(string $input , string $key , string $alg = 'HS256' )    {      $alg_config = array (        'HS256' => 'sha256'      );      return self::base64UrlEncode(hash_hmac( $alg_config [ $alg ], $input , $key ,true));    } }      //测试和官网是否匹配begin    $payload = array ( 'sub' => '1234567890' , 'name' => 'John Doe' , 'iat' =>1516239022);    $jwt = new Jwt;    $token = $jwt ->getToken( $payload );    echo "<pre>" ;    echo $token ;      //对token进行验证签名    $getPayload = $jwt ->verifyToken( $token );    echo "<br><br>" ;    var_dump( $getPayload );    echo "<br><br>" ;    //测试和官网是否匹配end      //自己使用测试begin    $payload_test = array ( 'iss' => 'admin' , 'iat' =>time(), 'exp' =>time()+7200, 'nbf' =>time(), 'sub' => 'www.admin.com' , 'jti' =>md5(uniqid( 'JWT' ).time()));;    $token_test =Jwt::getToken( $payload_test );    echo "<pre>" ;    echo $token_test ;      //对token进行验证签名    $getPayload_test =Jwt::verifyToken( $token_test );    echo "<br><br>" ;    var_dump( $getPayload_test );    echo "<br><br>" ;    //自己使用时候end

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.jianshu.com/p/0ac579e1384c

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容