thinkphp 8.0 实现 jwt 认证需构建认证、续期、黑名单、透传、权限分离五层协同链路;必须用 firebase/php-jwt:^6.10,密钥从环境变量读取并 trim,签发含 iat/exp/jti 的标准 payload,中间件校验需防头透传、正则提取、key 对象解码及 leeway 容错,权限与认证分离,登出入 redis 黑名单。

ThinkPHP 8.0 实现 JWT 身份认证,关键不是“写个中间件解析 token”,而是构建一条五层协同的稳定链路:认证、续期、黑名单、透传、权限分离。跳过任一环,都会出现 token 过期不续、登出仍可用、权限被绕过等问题。
选对库并锁死版本
必须用 firebase/php-jwt:^6.10,不能装 v7.x(要求 PHP ≥ 8.1,而 TP8 主流仍跑在 PHP 7.4–8.0)。执行:
composer require firebase/php-jwt:^6.10- 密钥从环境变量读取:
$_ENV['JWT_SECRET'],且用trim()去首尾空格 - 生成密钥推荐:
bin2hex(openssl_random_pseudo_bytes(32)),长度 64 位,别手写 "123456"
安全签发 token
在登录成功后生成 token,payload 必须含标准字段,且类型严格为整型时间戳:
-
iat(签发时间)和exp(过期时间)用time()+ 秒数,如time() + 3600 - 强制注入
jti(唯一标识),用于登出黑名单:uniqid('', true) - 添加业务字段如
uid、role、device,但绝不放密码、手机号、邮箱等敏感信息 - 签名时显式指定算法:
JWT::encode($payload, $secret, 'HS256')
中间件里正确校验 token
新建 app/middleware/AuthToken.php,核心逻辑要防三类坑:
- Web 服务器必须透传头:Nginx 加
proxy_set_header Authorization $http_authorization;;Apache 启用mod_headers并加RequestHeader set Authorization "%{HTTP:Authorization}e" - 提取 token 用正则:
preg_match('/^Bearer\s+(?<token>[^\s]+)$/i', $auth, $m)</token>,避免explode(' ', $auth)[1]因空格异常崩掉 - 解码时三项缺一不可:
JWT::decode($token, new Key($secret, 'HS256'), ['HS256']),漏掉算法数组或不用Key对象会触发SignatureInvalidException - 设时间容错:
JWT::$leeway = 60,防手机端 NTP 不准导致误判过期
权限与上下文分离设计
认证中间件只做一件事:核验 token 有效性,并把用户信息注入请求上下文,不查库、不跳转、不返回 JSON:
- 校验通过后调用:
$request->withAttribute('auth', (array)$payload) - 权限校验交给独立中间件(如
AuthRule.php),根据路由名 +$payload->role或$payload->scope动态比对 - 登出即加入黑名单:Redis 存
jti+exp,校验前先查是否存在 - 无感刷新靠滑动窗口:每次合法请求检查剩余有效期,若
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











