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

php 后端实现JWT认证方法示例

发布:smiling 来源: PHP粉丝网  添加日期:2021-10-27 15:20:14 浏览: 评论:0 

这篇文章主要介绍了php 后端实现JWT认证方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

JWT是什么

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

它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。它具备两个特点:

简洁(Compact):可以通过URL, POST 参数或者在 HTTP header 发送,因为数据量小,传输速度快

自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库

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

Tags: php后端 JWT认证

分享到: