必须用完整包名 firebase/php-jwt 安装,PHP≥7.4;使用前需 use Firebase\JWT\JWT;签名算法传 JWT::ALG_HS256 常量,密钥须为非空字符串;鉴权失败多因 Authorization 头格式错误或密钥不一致;防重放需结合 jti 与 Redis 实现一次性校验。

composer install jwt 扩展时提示找不到包
不是所有叫 “jwt” 的包都能直接用,firebase/php-jwt 是最常用、维护最活跃的 PHP JWT 库,但 composer 默认不认 jwt 这个关键词。搜 composer require jwt 会失败,因为没这个包名。
- 必须用完整包名:
composer require firebase/php-jwt - 别手快写成
php-jwt或jwt-auth(那是 Laravel 插件,非通用库) - PHP 版本要 ≥ 7.4;如果项目还在用 7.2,
firebase/php-jwtv6+ 就装不上,得加版本约束:composer require firebase/php-jwt:^5.2
用 Firebase\JWT\JWT::encode() 生成 token 却报 Class not found
装完包不代表能直接用——firebase/php-jwt 不提供全局函数,全靠命名空间和自动加载。常见错误是忘了 use,或者用了过时的静态调用方式。
- 必须在文件顶部声明:
use Firebase\JWT\JWT; -
JWT::encode()的第三个参数(签名算法)不能传字符串"HS256",得传常量JWT::ALG_HS256(v6+ 要求) - 密钥(
$key)必须是字符串,不能是空、null或数组,否则运行时报InvalidArgumentException - 示例片段:
use Firebase\JWT\JWT; $payload = ['user_id' => 123, 'exp' => time() + 3600]; $key = 'your-secret-key'; $token = JWT::encode($payload, $key, JWT::ALG_HS256);
接口鉴权时 JWT::decode() 报 SignatureInvalidException
这不是代码写错了,八成是请求头或密钥对不上。JWT 鉴权失败里,签名不匹配占七成以上,而且错误信息很模糊,容易往解码逻辑上瞎查。
- 检查 Authorization 请求头格式:必须是
Bearer <token>,中间有空格,且Bearer首字母大写 - 服务端用的密钥(
$key)必须和签发时**完全一致**,包括空白符、编码(比如从 env 文件读取时是否 trim 了换行) - 别把 base64url 编码后的 token 拿去二次 decode——
JWT::decode()输入的是原始 token 字符串,不是解码后的部分 - 如果用 Nginx,确认没删掉带点号(
.)的 header,有些配置会过滤掉Authorization头
生产环境 token 过期后前端反复刷 token,后端怎么防重放
JWT 本身无状态,exp 字段只能防“过期后使用”,但拦不住“刚过期就重放”。真正的防重放得靠外部机制,JWT 只负责配合。
- 必须在 payload 里加
jti(JWT ID),值为唯一字符串(如uniqid()+ 用户 ID),并存到 Redis,设置和 token 相同的过期时间 - 每次
JWT::decode()前,先查 Redis 是否存在该jti;存在则拒绝,并立即删掉它(实现一次性) - 别依赖
iat或nbf做窗口校验——时钟不同步会让它不可靠 - 注意:Redis key 过期时间要略长于 token
exp(比如 +2 秒),避免因网络延迟导致误判










