thinkphp 5.0.18 不支持 jwt 开箱即用,需手动集成 firebase/php-jwt ^6.10(禁用 v7.x),配置环境变量密钥、修复 web 服务器 authorization 头透传,并在中间件中安全解析 token 后通过 request 属性传递 uid,不可依赖原生 auth 类。

ThinkPHP 5.0.18 不支持 JWT 开箱即用,必须手动集成 firebase/php-jwt 并绕过 Auth 类——直接调用 Auth::check() 会始终返回 false 或误判,因为它的底层依赖 session 文件或数据库状态,而 JWT 是无状态的。
安装兼容版本的 jwt 库(别踩 v7.x 的坑)
TP 5.0.18 通常运行在 PHP 7.2–7.4 环境,firebase/php-jwt v7.x 要求 PHP ≥ 8.1,装了就报错。必须锁死版本:
- 执行
composer require firebase/php-jwt:^6.10(不是^7.0,也不是不带版本号) - 确认
php -v输出为7.4.x或更低;若已是 PHP 8.0+,仍建议用^6.10保持与 TP5 兼容性 - 不要用
lcobucci/jwt:它在 TP5.0.18 的 autoloader 下常出现类找不到问题,firebase/php-jwt的命名空间和加载更稳定
从配置或环境变量读密钥,禁止硬编码
密钥一旦写死在代码里(比如 '123456' 或 md5('xxx')),上线即高危。TP5.0.18 没有原生 env 支持,需手动补:
- 在
config/app.php末尾加一项:'jwt_secret' => getenv('JWT_SECRET') ?: 'fallback_secret_here', - 部署时在 Web 服务器(Nginx/Apache)或 CLI 启动脚本中设环境变量:
export JWT_SECRET=$(openssl_random_pseudo_bytes 32 | base64) - 生成密钥务必用
openssl_random_pseudo_bytes(32),别手敲、别用时间戳或简单字符串 - 验证是否生效:在控制器里临时加
dump(config('jwt_secret'));,确保输出不是空或默认值
中间件里安全提取并校验 token
TP5.0.18 的 $request->header('authorization') 经常为空,不是你代码错了,是 Web 服务器没透传头:
- Nginx 配置必须含:
proxy_set_header Authorization $http_authorization;(缺这行,$http_authorization就不会进 PHP) - Apache 需启用
mod_headers,并在虚拟主机加:RequestHeader set Authorization "%{HTTP:Authorization}e" - 提取 token 别用
explode(' ', $auth)[1]——前端可能发Bearer\txxx或前后多空格,改用:preg_match('/^Bearer\s+(?<token>[^\s]+)$/i', $auth, $m) ? $m['token'] : null</token> - 校验时必须显式传算法数组:
JWT::decode($token, new Key(config('jwt_secret'), 'HS256'), ['HS256']);漏掉第三个参数会触发默认行为,但 token header 里 alg 不匹配就直接崩 - 加一行
JWT::$leeway = 60;,防客户端/服务端时间差导致ExpiredException(尤其手机端 NTP 不准)
payload 必须含 iat/exp,且类型必须是 int
少一个字段、类型不对,JWT::decode() 就抛 DomainException: Invalid token format,而不是告诉你缺啥:
- 签发时 payload 至少要有:
'iat' => time()、'exp' => time() + 3600、'jti' => uniqid() - 别用
date('U')或(new DateTime())->getTimestamp()——它们可能返回微秒级时间戳,iat/exp只认整数秒 - 别往 payload 塞
password、phone、email——JWT 是 base64url 编码,不是加密,前端打开 DevTools 就能解出明文 - 如果业务需要防重放,加
'nbf' => time() + 10(10 秒后才生效),但记得 decode 时要主动校验:if ($decoded->nbf > time()) { throw new Exception('Not valid yet'); }
最易被忽略的是:TP5.0.18 的中间件无法直接修改 $this->auth 或影响全局 Auth 实例,所以“让 JWT 和原有权限系统共存”的唯一可靠路径,是在中间件成功解析后,把 $decoded->uid 存到请求属性里($request->withAttribute('uid', $uid)),后续控制器再按需调用 RBAC 方法——别试图给 Auth 类打补丁。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











