应在 behaviors() 中配置自定义 JwtHttpBearerAuth 类统一校验 JWT,通过 Yii::$app->user->loginByAccessToken() 或实现 IdentityInterface 的 UserIdentity 加载用户,密钥从 params 读取、算法传 ['HS256'] 数组,严格处理 Authorization 头格式与异常日志。

怎么在 Yii2 控制器里验证 JWT Token
JWT 不是 Yii2 原生支持的认证方式,得靠 firebase/php-jwt 解析并校验。关键不是“怎么装包”,而是“在哪校验、谁来校验、校验失败怎么处理”。
典型错误是把验证逻辑塞进 beforeAction() 但没统一拦截未登录请求,或者直接在 action 里硬解 token 却忽略签名失效、过期、issuer 不匹配等细节。
- 必须用
Yii::$app->user->loginByAccessToken()或自定义UserIdentity实现,不能只解析完就放行 - 推荐在
behaviors()中配authenticator+ 自定义JwtHttpBearerAuth类,而不是每个 controller 写一遍JWT::decode() - 注意
JWT::decode()抛出的是DomainException、SignatureInvalidException等具体异常,别用裸try/catch (Exception)吞掉所有错误 - 密钥(
$key)建议从Yii::$app->params['jwtKey']读,别硬编码;算法固定用HS256,除非你真需要 RSA 并已配好公私钥
firebase/php-jwt 的 decode() 参数怎么填才不报错
JWT::decode() 第三个参数是算法数组,不是单个字符串——这是最常踩的坑。传 ['HS256'] 是对的,传 'HS256' 或 ['hs256'] 都会抛 InvalidArgumentException。
另一个隐形雷点:token 里的 exp 是秒级时间戳,但 PHP 默认时区影响 time(),如果服务器时区和生成 token 的服务不一致,可能误判过期。
立即学习“PHP免费学习笔记(深入)”;
- 必须传数组:
JWT::decode($token, $key, ['HS256']) -
$key类型必须是 string;如果是 base64 编码过的密钥,要先base64_decode() - 如果 token 含
nbf(not before),也要确保服务器时间准确,否则合法 token 被拒 - 不要自己拼
$payload->exp > time(),交给JWT::decode()自动校验,它内部已处理时区与精度问题
Yii2 UserIdentity 怎么对接 JWT payload
Yii2 的 UserIdentity 本质是靠 findIdentity() 和 getId() 拉用户数据,而 JWT 里通常只有 uid 或 sub 字段。这里不能直接返回 payload 对象,得查库或缓存还原完整用户实例。
常见错误是把 JWT::decode() 结果当 UserIdentity 返回,导致后续调 $user->can() 或 $user->getIsGuest() 失败。
-
findIdentity()必须返回UserActiveRecord 实例(或实现IdentityInterface的类),不能返回stdClass - 推荐在
findIdentity()里用$payload->sub或$payload->uid查询数据库,例如return static::findOne(['id' => $payload->sub]) - 如果 token 里没带用户 ID,而是用 email 或 username,注意 SQL 注入风险,用参数绑定
-
getId()必须返回标量(int/string),不能返回对象或数组,否则Yii::$app->user->id会出错
为什么 postman 测试老是 401,但 token 明明能用 jwt.io 解开
jwt.io 只校验签名和结构,不检查 iss、aud、nbf、服务器时间、请求头格式这些 Yii2 实际运行时会触发的校验点。
最常漏的是 Authorization 请求头格式不对:必须是 Bearer <token></token>(注意 Bearer 后有一个空格),少空格、多空格、写成 Token 或 JWT 都会失败。
- 检查请求头:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... - 确认 token 没被 URL 编码过(postman 自动编码 ?token=xxx 里的值,要手动解码再贴)
- 用
Yii::info($e->getMessage(), 'jwt')打日志,别只依赖 HTTP 状态码——ExpiredException和SignatureInvalidException都返回 401,但原因完全不同 - 如果用 nginx,确认没过滤掉
Authorization头(需加fastcgi_pass_request_headers on;和proxy_pass_request_headers on;)
JWT 在 Yii2 里不是插件式开关,它串起了请求头解析、异常映射、用户加载、权限钩子四个环节。少一个环节,token 就只是一串能解开但无法落地的字符串。











