<?php declare(strict_types=1); ini_set('display_errors', 'On'); error_reporting(-1); require_once __DIR__ . '/JWT/vendor/autoload.php'; // 引入JWT库 // 使用多台服务器时,服务器之间的系统时间可能不同步,A服签发JWT后客户端立即发往B服验证,如果B服比A服慢了几秒,就会出现验证失 // 败的情况,而通过设置“JWT::$leeway”属性就能够解决这个问题,它能容许两台服务器的系统时间有指定范围内的差距,若设置为0则要 // 求所有服务器的系统时间完全同步。服务器之间的系统时间差异通常不会太大,一般设为60秒就可以满足实际需求。 Firebase\JWT\JWT::$leeway = 60; // 默认为0,单位:秒 /** * JSON Web Token(JWT)工具类 */ class JWTTool { private const ISS = 'www.manong.life'; // JWT的签发者 private const KEY = 'www.manong.life'; // 加解密所需的密钥 private const ALG = 'HS512'; // 加密使用的哈希算法,缺省则为'HS256' private const EXP = 7200; // JWT失效时间(注意不宜过长,一般为2~24小时),单位:秒 /** * JWT编码(即生成JWT) * * @param array $data 自定义数据(支持各种基本数据类型) * @return string JWT */ public static function encode(mixed $data): string { $time = time(); // 构造JWT的载荷(载荷可为空数组,但建议至少设置生效时间和失效时间) $payload = [ 'iss' => self::ISS, // JWT的签发者 'iat' => $time, // JWT生成时间 'nbf' => $time, // JWT生效时间,通常生成即生效,若想该JWT在10分钟后才生效可设为($time + 600) 'exp' => $time + self::EXP, // JWT失效时间 'data' => $data, // JWT的自定义数据 ]; return Firebase\JWT\JWT::encode($payload, self::KEY, self::ALG); } /** * JWT解码 * * @param string $jwt JWT * @return mixed 自定义数据(签发JWT时自定义数据是什么类型就返回什么类型),若JWT不合法或已过期则返回null */ public static function decode(string $jwt): mixed { $data = null; $key = new Firebase\JWT\Key(self::KEY, self::ALG); $payload = null; try { // JWT解码方法返回的是对象格式的整个载荷,若JWT不合法或已过期期则会抛出异常 $payload = Firebase\JWT\JWT::decode($jwt, $key); } catch (Exception $e) { unset($e); } // JWT解码成功(即获得载荷),开始从载荷里取出自定义数据 if ($payload instanceof stdClass) { // 将对象格式的载荷转为JSON字符串格式 try { $payload = json_encode($payload, JSON_THROW_ON_ERROR); } catch (JsonException $e) { unset($e); } // 将JSON字符串格式的载荷转为数组格式 if (is_string($payload)) { try { $payload = json_decode($payload, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { unset($e); } } // 获取载荷里的自定义数据(即data部分) if (is_array($payload) && isset($payload['data'])) { $data = $payload['data']; } } return $data; } } /** * 打印变量的相关信息 * * @param mixed $value 要打印的表达式 * @param mixed ...$values 更多要打印的表达式 * @return void echo */ function v(mixed $value, mixed ...$values): void { ob_start(); // 打开输出控制缓冲 var_dump($value); echo ob_get_clean(); // 从缓冲区获取var_dump()的内容,然后清空缓冲区 foreach ($values as $v) { v($v); // 递归 } } // 生成(签发)JWT的自定义数据 $data = ['uid' => 9527, 'name' => '张三', 'gender' => '男', 'birth' => 2003]; // 生成JWT(返回给客户端,客户端需将JWT保存到本地) $jwt = JWTTool::encode($data); echo "JWT:$jwt" . PHP_EOL; // JWT:{$header}.{$payload}.{$signature} // 解码JWT,若JWT不合法或已过期则返回null $profile = JWTTool::decode($jwt); v($profile); // array(4) { // ["uid"]=> // int(9527) // ["name"]=> // string(6) "张三" // ["gender"]=> // string(3) "男" // ["birth"]=> // int(2003) // } //========== 总结 ==========// // 1、JWT由头部(header)、载荷(payload)、签名(signature)三部分组成,每部分之间用小数点隔开。 // 2、开发者的自定义数据就保存在载荷里面,需要注意的是载荷只是进行了base64_encode()处理,并没有加密,所以开发者务必先自行把自定义数 // 据加密,建议使用openssl_encrypt()或openssl_public_encrypt()加密,然后再签发JWT。 // 3、不要在JWT里保存太多自定义数据,只保存一两个重要的数据即可,如用户UID、账号之类的数据(再次提醒,自定义数据务必加密)。 // 4、使用JWT保存登录态很简单,就是客户端向服务端提交账号密码并通过身份认证后,服务端不保存session,而是向客户端返回一个包含其身份 // 信息的Token(即JWT),客户端需将JWT保存到本地,后续客户端向服务器端发起请求都要传递JWT,服务端验证JWT合法后才响应其请求。 // 5、客户端向服务端传递JWT的方式有多种,包括HTTP头、URL、POST等,通常建议使用名为Authorization的HTTP头将JWT传递给服务端。 // 6、JWT一旦签发给客户端就无法撤销,只能等其到期失效,故失效时间不宜过长,一般为2~24小时。开发者可提供刷新JWT功能,方法也很简单, // 就是从JWT中提取出自定义数据,再用这些数据签发新的JWT给客户端,客户端用新JWT替换掉旧JWT即可。 // 7、JWT可以签发给任意客户端,包括但不限于Web站点(cookie和localStorage)、Android、iOS、微信小程序等客户端,只要该客户端可以保存 // JWT字符串即可。
Copyright © 2024 码农人生. All Rights Reserved