唯一应安装的包是firebase/php-jwt,php 7.4–8.0用^6.10,8.1+用^7.0;必须用完整包名,避免装错过时包;encode需三参数(payload、密钥、算法字符串),decode需传算法数组和key对象,密钥严禁硬编码。

直接用 composer require firebase/php-jwt 就够了
别被“PHP-JWT”这个名字误导——官方推荐、维护最活跃、兼容性最好的 JWT 库就是 firebase/php-jwt,不是 php-jwt 或其他同名包。执行命令后,Composer 会自动下载并注册 autoloader,JWT 类就能直接用了。
常见错误:有人搜 “php jwt” 后装了过时的 php-jwt(无命名空间、不支持 PSR-4),结果调用 JWT::encode() 报 Class 'JWT' not found。认准包名 firebase/php-jwt,版本建议锁定 ^6.10 或 ^7.0(PHP 8.1+ 推荐 v7)。
- PHP 7.4–8.0 → 用
firebase/php-jwt:^6.10 - PHP 8.1+ → 用
firebase/php-jwt:^7.0(v7 要求 ext-mbstring,且默认返回JWK对象而非数组) - 别手动 require 或 include — Composer 自动处理 autoload,只要项目根目录有
vendor/autoload.php并已引入即可
JWT::encode() 和 JWT::decode() 的参数不能错位
签名密钥类型、算法、返回结构三者必须对齐,否则要么生成无效 token,要么解码直接抛 DomainException 或 UnexpectedValueException。
典型场景:用 HMAC-SHA256 签名(最常用),密钥是字符串;但传入 null 密钥、或把密钥当数组传、或算法写成 HS512 却用 HS256 密钥长度,都会失败。
-
JWT::encode($payload, $secretKey, 'HS256')—— 第三个参数是算法名字符串,不是常量 -
$payload必须是关联数组,且至少含iat(签发时间)、exp(过期时间),否则JWT::decode()默认校验会失败 -
JWT::decode($token, $secretKey, ['HS256'])—— 第三个参数是允许的算法数组,不是单个字符串;漏掉这个数组会报Algorithm not allowed - v7 中
decode()返回stdClass对象,不是数组;要取字段得用->,比如$decoded->user_id
Token 校验失败时,错误信息藏在异常 message 里
不要靠 try/catch 捕获泛型 Exception 然后忽略细节。Firebase JWT 抛出的具体异常类型能快速定位问题:
-
DomainException:密钥为空、算法不匹配、token 格式错误(如缺少点号分隔) -
UnexpectedValueException:签名无效(密钥错/被篡改)、exp已过期、nbf(生效前)未到时间 -
InvalidArgumentException:payload 不是数组、header 不合法
实操建议:开发时打开 ini_set('display_errors', 1),捕获异常后直接 echo $e->getMessage(),比查文档快得多。上线后记录日志,但别把原始异常暴露给前端。
别把私钥硬编码在代码里,也别用 $_ENV['JWT_SECRET'] 直接读
密钥泄漏 = 全站 token 可伪造。本地开发可用环境变量,但必须确保 .env 不提交、Web 服务器不公开该文件;生产环境优先用 PHP-FPM 的 env[JWT_SECRET] 配置,或通过 secrets manager 注入。
容易踩的坑:
- 用
getenv('JWT_SECRET')但没调用putenv()或未启用variables_order中的E,导致返回 false - 把密钥写死在 config.php 里,Git 提交后全网可查
- 用
file_get_contents('/var/secrets/jwt.key')但没做权限检查(文件需 chmod 400,属主为 web server 用户)
复杂点在于:密钥轮换时,旧 token 还没过期,新旧密钥得同时支持验证 —— 这时 JWT::decode() 的第二个参数得换成闭包,动态返回对应密钥,而不是固定字符串。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











