推荐直接使用 firebase/php-jwt,轻量、文档清晰、无框架绑定;需启用 OpenSSL 和 JSON 扩展,正确使用 JWT::encode()/decode() 及 Key 实例,注意 Web 服务器透传 Authorization 头。

直接装 firebase/php-jwt 就够了,别碰其他“JWT认证扩展包”
市面上很多教程推荐的 lcobucci/jwt 或所谓“Laravel JWT 认证包”(如 tymon/jwt-auth)本质是封装层,对新手反而增加理解成本。真要验签、生成 token,firebase/php-jwt 足够轻量、文档清晰、无框架绑定,且 PHP 7.4+ 原生支持。
执行安装命令即可:
composer require firebase/php-jwt
注意:它不自动注册 autoloader —— 你不用管,Composer 已处理;但你要确保项目已运行 composer install 或 composer dump-autoload(尤其在手动改过 composer.json 后)。
PHP 环境必须启用 openssl 和 json 扩展
firebase/php-jwt 默认用 HS256 签名,看似不依赖 OpenSSL,但一旦切换到 RS256 或 ES256(生产环境强烈建议),就会报错:Signature verification failed 或直接抛出 DomainException: OpenSSL error。
立即学习“PHP免费学习笔记(深入)”;
- 检查是否启用:
php -m | grep -E 'openssl|json' - 常见坑:
php.ini中extension=openssl被注释,或 CLI 和 Web SAPI 使用不同配置(比如php -v显示有 openssl,但phpinfo()里没有) - Ubuntu/Debian 下缺 OpenSSL:运行
sudo apt install php-openssl,然后重启 web server(sudo systemctl restart apache2或sudo systemctl restart php8.1-fpm)
别用 base64_encode() 手动拼 token,老老实实用 JWT::encode() 和 JWT::decode()
很多人抄网上代码,自己拼 header.payload.signature 字符串,再 base64url 编码——这极易出错:漏去填充、没替换 +//、大小写混淆。JWT 规范要求的是 base64url 编码(非标准 base64),而 firebase/php-jwt 内部已正确处理。
正确用法示例:
$secret = 'your_32_byte_secret_here'; $payload = [ 'iss' => 'https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39', 'iat' => time(), 'exp' => time() + 3600, 'user_id' => 123 ];// 生成 token $token = JWT::encode($payload, $secret, 'HS256');
// 验证并解析 token try { $decoded = JWT::decode($token, new Key($secret, 'HS256')); echo $decoded->user_id; // 123 } catch (Exception $e) { echo 'Invalid token: ' . $e->getMessage(); } ?>
关键点:
-
JWT::decode()第二个参数必须是Key实例(v6.0+ 强制要求),不能传字符串 -
HS256密钥长度建议 ≥32 字节(即 256 bit),太短会被警告 - 如果要用公私钥(
RS256),new Key($public_key, 'RS256')的第一个参数必须是 PEM 格式字符串(含-----BEGIN PUBLIC KEY-----头尾)
Web 服务器需透传 Authorization 请求头
前端发请求带 Authorization: Bearer xxxxx,但 Nginx/Apache 默认会过滤该 header,导致 PHP 的 $_SERVER['HTTP_AUTHORIZATION'] 为空。
Nginx 配置需加:
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
# 其他 fastcgi_param ...
}Apache 用户确保 .htaccess 或虚拟主机中启用了 RewriteEngine On,并添加:
RewriteCond %{HTTP:Authorization} ^(.*)$
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]验证是否生效:在 PHP 中打印 var_dump($_SERVER['HTTP_AUTHORIZATION'] ?? 'MISSING');,没输出就说明 header 没透传过去。
最常被忽略的是:JWT 的 exp 时间戳是秒级整数,不是毫秒;密钥硬编码在代码里只适合开发,上线必须从环境变量读取;JWT::decode() 抛异常时不要裸露堆栈,尤其别把 $e->getMessage() 直接返回给前端。











