PHP中的JWT令牌:实现完全指南
JWT(JSON Web Token)是一种基于JSON格式的开放标准(RFC 7519),用于创建访问令牌。在PHP中,JWT被广泛用于在REST API、单页应用程序(SPA)和微服务中实现无状态身份验证(stateless authentication)。
在本文中,我们将详细讲解如何在PHP中使用JWT令牌:从库的安装到令牌的创建、验证与刷新。
什么是JWT,为什么需要它?
JWT由三部分组成,各部分之间用点号分隔:
- Header(头部) — 包含令牌类型(JWT)和签名算法(例如HS256或RS256)。
- Payload(有效载荷) — 包含声明(claims):用户标识符、角色、签发时间(iat)、过期时间(exp)以及其他数据。
- Signature(签名) — 通过对头部和有效载荷进行哈希处理并使用密钥生成。
JWT的主要优势:
- 无需在服务器上存储会话(无状态)。
- 可以包含任意数据(例如用户角色)。
- 适用于不同域名和移动应用程序。
- 无需访问数据库即可轻松验证。
安装firebase/php-jwt库
为了在PHP中使用JWT,我们将使用流行的库firebase/php-jwt。通过Composer进行安装:
composer require firebase/php-jwt安装后,项目中会出现Composer自动加载,需要引入它:
require_once 'vendor/autoload.php';
use Firebase\\JWT\\JWT;use Firebase\\JWT\\Key;创建JWT令牌
要创建令牌,需要定义密钥($secretKey)并构建有效载荷。示例:
use Firebase\\JWT\\JWT;
$secretKey = 'your-256-bit-secret-key-here';$issuedAt = time();$expirationTime = $issuedAt + 3600; // 令牌有效期为1小时
$payload = [ 'iss' => 'pythonlib.ru', // 签发者 'iat' => $issuedAt, // 签发时间 'exp' => $expirationTime, // 过期时间 'sub' => 123, // 用户标识符 'role' => 'admin' // 自定义数据];
$jwt = JWT::encode($payload, $secretKey, 'HS256');echo $jwt;结果将得到一个类似这样的字符串:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJweXRob25saWIucnUiLCJpYXQiOjE3Mjg0MDAwMDAsImV4cCI6MTcyODQwMzYwMCwic3ViIjoxMjMsInJvbGUiOiJhZG1pbiJ9.signature
验证和解码JWT
当从客户端收到令牌时(例如,从Authorization: Bearer <token>头部),需要对其进行验证:
use Firebase\\JWT\\JWT;use Firebase\\JWT\\Key;
$secretKey = 'your-256-bit-secret-key-here';$jwt = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
try { $decoded = JWT::decode($jwt, new Key($secretKey, 'HS256')); $userId = $decoded->sub; $role = $decoded->role; echo "用户 #{$userId} 角色为 {$role} 已授权。";} catch (\\Exception $e) { http_response_code(401); echo "错误: " . $e->getMessage();}重要提示:该库会自动检查令牌的过期时间(exp)和签发时间(iat)。如果令牌已过期或无效,将抛出异常。
刷新JWT(Refresh Token)
为了提高安全性,JWT通常设置为短生命周期(15–60分钟)。对于长时间会话,可以使用Refresh Token——这是一个单独的令牌,存储在数据库中,允许在不重新输入用户名/密码的情况下获取新的Access Token。
刷新实现的示例:
function refreshAccessToken(string $ref