JWT签名验证失败主因是密钥不一致,需检查配置密钥、中间件传参、环境变量加载及base64解码合法性;API场景Auth::check()失效因依赖session,应改用JWTAuth解析;UserNotDefinedException源于sub字段查不到用户记录,需核对模型主键、数据表及软删除状态;Authorization头丢失多因Nginx/Apache未透传,须配置请求头转发。

JWT token 解析失败时,getPayload() 报 InvalidSignatureException
签名验证失败不等于 token 过期或格式错误,大概率是密钥不一致。ThinkPHP 默认用 config('jwt.secret') 验证,但中间件里可能手动传了别的密钥,或者环境变量没加载进来。
实操建议:
- 检查
config/jwt.php中的secret是否和生成 token 时用的完全一致(注意前后空格、换行) - 在中间件中加一行日志:
Log::info('JWT secret used', ['secret_len' => strlen(config('jwt.secret'))]);,确认实际读到的密钥长度是否异常(比如为 0) - 如果用了
base64_decode()处理密钥,确保原始字符串是合法 base64;否则解码后变成乱码,签名必然失败 - 开发环境开启
JWT_DEBUG = true,会抛出更具体的错误堆栈,定位到FireflyIII\Jwt\Parser或firebase/php-jwt的哪一行
中间件跳过登录校验,但 Auth::check() 仍返回 false
ThinkPHP 的 Auth 门面默认依赖 session,而 API 场景通常禁用 session,改用 token 存储在请求头。此时 Auth::check() 本质是在查 session 里的用户 ID,自然为空。
实操建议:
- 不要在 API 中间件里调用
Auth::check(),改用JWTAuth::parseToken()->authenticate()或直接解析 token 获取用户信息 - 确认中间件注册顺序:必须在
AllowCrossDomain之后、路由分发之前执行,否则Authorization头可能被过滤或覆盖 - 如果用了多 guard(如
api和web),务必指定 guard:Auth::guard('api')->check(),否则默认走web - 检查
config/auth.php中defaults.guard是否误配为web,导致所有未显式指定 guard 的调用都走错通道
调试时 token 明明有效,JWTAuth::parseToken()->toUser() 却抛 UserNotDefinedException
这个异常不是 JWT 层的问题,而是 ThinkPHP 尝试从 token payload 的 sub 字段查用户模型时,没找到对应记录,或模型配置有误。
实操建议:
- 先用
JWTAuth::parseToken()->getPayload()打印 payload,确认sub字段值存在且是数字(非字符串 ID) - 检查用户模型的主键是否为
id;如果不是(比如叫user_id),需在模型里显式定义:protected $primaryKey = 'user_id'; - 确认模型的
$table指向正确数据表,且该表中确实存在sub对应的记录(常见于测试环境清库后忘记重置 token) - 如果用户模型用了软删除,确保 token 中的
sub对应的是未被删除的用户——否则toUser()内部的find()会静默返回 null,最终触发该异常
前端传了 Bearer xxx,但后端收不到 Authorization 头
不是代码问题,是服务器或网关拦截了该请求头。Nginx 默认不透传 Authorization,Apache 可能因 mod_rewrite 规则丢失,CORS 预检也常因此失败。
实操建议:
- Nginx 配置里加:
proxy_set_header Authorization $http_authorization;,并确保underscores_in_headers on;(否则下划线字段被丢弃) - Apache 下检查
.htaccess是否有RewriteRule覆盖了请求头,或添加:SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 - 用
curl -H "Authorization: Bearer xxx" http://localhost/api/test直连 PHP-FPM,绕过 Web 服务器,确认是否真为中间层问题 - 浏览器控制台 Network 标签页看请求头是否发出,再看响应头是否有
Access-Control-Allow-Headers: Authorization,没有就补上
调试 JWT 鉴权失败,真正卡住人的往往不是算法或语法,而是密钥加载时机、请求头传递链路、以及模型与 token 字段的隐式耦合——这些地方一漏,日志里只显示“鉴权失败”,但根本看不出断在哪一环。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










