本文目录导读:

我来详细说明在PHP项目中实现JWT(JSON Web Token)的几种方式。
使用第三方库(推荐)
Firebase JWT 库(最常用)
安装:
composer require firebase/php-jwt
基础使用:
<?php
require_once 'vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtService {
private $key;
private $algorithm = 'HS256';
public function __construct() {
// 密钥存储在环境变量中
$this->key = getenv('JWT_SECRET_KEY');
}
// 生成 Token
public function generateToken($userId, $expireTime = 3600) {
$payload = [
'iss' => 'your-app-name', // 签发者
'iat' => time(), // 签发时间
'exp' => time() + $expireTime, // 过期时间
'sub' => $userId, // 用户ID
'role' => 'user' // 可以添加自定义字段
];
return JWT::encode($payload, $this->key, $this->algorithm);
}
// 验证 Token
public function validateToken($token) {
try {
$decoded = JWT::decode($token, new Key($this->key, $this->algorithm));
return (array) $decoded;
} catch (\Exception $e) {
// 处理各种异常
throw new \Exception('Token验证失败:' . $e->getMessage());
}
}
// 刷新 Token
public function refreshToken($oldToken) {
$payload = $this->validateToken($oldToken);
// 生成新的Token
return $this->generateToken($payload['sub']);
}
}
完整实现示例
用户登录并生成Token
<?php
// login.php
require_once 'vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class AuthController {
private $jwtKey;
public function __construct() {
$this->jwtKey = 'your-secret-key-here';
}
// 用户登录
public function login($username, $password) {
// 验证用户(示例简化)
$user = $this->authenticateUser($username, $password);
if (!$user) {
http_response_code(401);
echo json_encode(['error' => '登录失败']);
return;
}
// 生成Token
$token = $this->createToken($user);
echo json_encode([
'token' => $token,
'user' => [
'id' => $user['id'],
'username' => $user['username']
]
]);
}
private function createToken($user) {
$payload = [
'iss' => 'my-api',
'iat' => time(),
'exp' => time() + (7 * 24 * 60 * 60), // 7天过期
'user_id' => $user['id'],
'username' => $user['username'],
'role' => $user['role']
];
// 可选:添加 Refresh Token
$refreshToken = bin2hex(random_bytes(32));
return [
'access_token' => JWT::encode($payload, $this->jwtKey, 'HS256'),
'refresh_token' => $refreshToken,
'token_type' => 'Bearer',
'expires_in' => 7 * 24 * 60 * 60
];
}
// 验证请求中的Token
public function authenticateRequest() {
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (empty($authHeader) || !str_starts_with($authHeader, 'Bearer ')) {
http_response_code(401);
echo json_encode(['error' => '缺少认证信息']);
exit;
}
$token = substr($authHeader, 7);
try {
$decoded = JWT::decode($token, new Key($this->jwtKey, 'HS256'));
return (array) $decoded;
} catch (\Exception $e) {
http_response_code(401);
echo json_encode(['error' => 'Token无效或已过期']);
exit;
}
}
}
中间件实现
<?php
// middleware.php
class JwtMiddleware {
private $jwtService;
private $excludedPaths = ['/login', '/register'];
public function __construct($jwtService) {
$this->jwtService = $jwtService;
}
// 路由中间件
public function handle($requestPath) {
// 排除不需要认证的路径
if (in_array($requestPath, $this->excludedPaths)) {
return true;
}
$token = $this->getBearerToken();
if (!$token) {
$this->unauthorizedResponse('缺少Token');
}
try {
$payload = $this->jwtService->validateToken($token);
// 将用户信息保存到请求中
$_REQUEST['user'] = $payload;
return true;
} catch (\Exception $e) {
$this->unauthorizedResponse($e->getMessage());
}
}
private function getBearerToken() {
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
return $matches[1];
}
return null;
}
private function unauthorizedResponse($message) {
http_response_code(401);
echo json_encode(['error' => $message]);
exit;
}
}
使用其他JWT库
Lcobucci JWT(另一个流行选择)
composer require lcobucci/jwt
<?php
require_once 'vendor/autoload.php';
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
class JwtHandler {
private $config;
public function __construct() {
$this->config = Configuration::forSymmetricSigner(
new Sha256(),
InMemory::base64Encoded('your-base64-encoded-secret')
);
}
// 生成Token
public function createToken($userId) {
$now = new DateTimeImmutable();
$token = $this->config->builder()
->issuedBy('your-app')
->permittedFor('your-client')
->identifiedBy(bin2hex(random_bytes(16)))
->issuedAt($now)
->canOnlyBeUsedAfter($now)
->expiresAt($now->modify('+1 hour'))
->withClaim('user_id', $userId)
->getToken($this->config->signer(), $this->config->signingKey());
return $token->toString();
}
// 验证Token
public function validateToken($tokenString) {
try {
$token = $this->config->parser()->parse($tokenString);
// 验证签名
if (!$token->verify($this->config->signer(), $this->config->signingKey())) {
throw new \Exception('签名验证失败');
}
// 检查是否过期
if ($token->isExpired(new DateTimeImmutable())) {
throw new \Exception('Token已过期');
}
return $token->claims();
} catch (\Exception $e) {
throw $e;
}
}
}
安全建议
密钥管理
<?php
// config.php
define('JWT_SECRET', getenv('JWT_SECRET'));
define('JWT_ALGORITHM', 'HS256');
define('JWT_EXPIRY', 3600); // 1小时
// .env 文件
// JWT_SECRET=your-256-bit-secret-key-here
Refresh Token 实现
<?php
class RefreshTokenService {
private $db; // 数据库连接
// 保存Refresh Token到数据库
public function saveRefreshToken($userId, $refreshToken, $expiresAt) {
$sql = "INSERT INTO refresh_tokens (user_id, token, expires_at)
VALUES (?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId, $refreshToken, $expiresAt]);
}
// 使用Refresh Token获取新的Access Token
public function refreshAccessToken($refreshToken) {
// 验证Refresh Token
$token = $this->getValidRefreshToken($refreshToken);
if (!$token) {
throw new \Exception('Refresh Token无效');
}
// 删除旧的Refresh Token
$this->deleteRefreshToken($refreshToken);
// 生成新的Access Token和Refresh Token
$newAccessToken = $this->generateAccessToken($token['user_id']);
$newRefreshToken = $this->generateRefreshToken();
// 保存新的Refresh Token
$this->saveRefreshToken(
$token['user_id'],
$newRefreshToken,
date('Y-m-d H:i:s', strtotime('+30 days'))
);
return [
'access_token' => $newAccessToken,
'refresh_token' => $newRefreshToken
];
}
}
前端使用示例
// 前端请求示例
fetch('https://api.example.com/protected-endpoint', {
method: 'GET',
headers: {
'Authorization': `Bearer ${localStorage.getItem('access_token')}`,
'Content-Type': 'application/json'
}
})
.then(response => {
if (response.status === 401) {
// Token过期,尝试刷新
return refreshToken();
}
return response.json();
});
完整项目结构建议
project/
├── composer.json
├── .env
├── config/
│ └── jwt.php
├── src/
│ ├── JwtService.php
│ ├── JwtMiddleware.php
│ └── AuthController.php
└── vendor/
这就是PHP实现JWT的完整方案,建议使用成熟的第三方库(如 firebase/php-jwt),并注意密钥安全和Token有效期管理。