当前位置:首页 > PHP教程 > php高级应用 > 列表

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

发布:smiling 来源: PHP粉丝网  添加日期:2022-01-21 20:32:05 浏览: 评论:0 

这篇文章主要介绍了php实现JWT(json web token)鉴权实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

JWT是什么

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

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

以下示例以JWT官网为例

header部分:

  1.  "alg": "HS256", 
  2.  "typ": "JWT" 

对应base64UrlEncode编码为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

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

payload部分:

  1.  "sub": "1234567890", 
  2.  "name": "John Doe", 
  3.  "iat": 1516239022 

对应base64UrlEncode编码为:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

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

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

signature部分:

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

对应的签名为:keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU

最终得到的JWT的Token为(header.payload.signature):eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU

说明:对header和payload进行base64UrlEncode编码后进行拼接。通过key(这里是123456)进行HS256算法签名。

JWT使用流程

初次登录:用户初次登录,输入用户名密码

密码验证:服务器从数据库取出用户名和密码进行验证

生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT

返还JWT:服务器的HTTP RESPONSE中将JWT返还

带JWT的请求:以后客户端发起请求,HTTP REQUEST

HEADER中的Authorizatio字段都要有值,为JWT

服务器验证JWT

PHP如何实现JWT

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

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

Tags: JWT json token

分享到: