Laravel 9.0自定义JWT Token生成问题:与当前认证用户无关
问题描述
需要生成一个不关联当前认证用户的自定义JWT Token,用于SSO链接实现本应用与第三方应用集成。尝试用JWTFactory设置自定义声明,再通过JWTAuth::encode($customPayload, $customKey)生成Token,但生成的JWT仍关联当前认证用户,且自定义声明未生效,payload里反而包含当前用户的声明。相关PHP代码如下:
$payload = JWTFactory::sub('123456') ->exp(date('Y-m-d H:i:s', strtotime('+ 60 minute'))) ->iss('https://localhost:3001') ->aud('https://third.application.com') ->make(); $keyBytes = base64_encode('custom_key_here'); $token = JWTAuth::encode($payload, $keyBytes, 'HS256');
更新:等效的NodeJS代码如下:
const jwt = require('jsonwebtoken') const sharedKey = 'IUElRCpHLUthUGRSZ1VrWHAycrzV2OHkvQj9FKEgrTWI=' const keyBytes = Buffer.from(sharedKey, 'base64') const payload = { sub: '123456', exp: Math.floor(Date.now() / 1000) + (60 * 60), iss: 'https://localhost:3001', aud: 'https://third.application.com' } const token = jwt.sign(payload, keyBytes, { algorithm: 'HS256' })
解决方案
1. 生成无用户上下文的Payload
Laravel的JWTFactory如果默认调用,会自动绑定当前认证用户的上下文。要生成完全独立的Payload,必须显式创建新的工厂实例,避免继承认证上下文:
use Tymon\JWTAuth\Facades\JWTFactory; // 用new()创建无关联的工厂实例 $payload = JWTFactory::new() ->sub('123456') ->exp(time() + 3600) // 注意:exp必须是Unix时间戳,不能是日期字符串 ->iss('https://localhost:3001') ->aud('https://third.application.com') ->make();
原代码中exp用日期字符串是错误的,JWT标准要求该字段为Unix时间戳,这也是Payload异常的原因之一。
2. 对齐密钥处理逻辑
你的PHP代码和NodeJS代码的密钥处理逻辑完全相反:
- NodeJS是把base64编码的密钥解码为字节
- PHP原代码是把普通字符串编码为base64
正确的PHP处理方式应该和NodeJS对齐:
// 如果共享密钥是base64格式字符串,解码为原始字节 $sharedKey = 'IUElRCpHLUthUGRSZ1VrWHAycrzV2OHkvQj9FKEgrTWI='; $keyBytes = base64_decode($sharedKey); // 如果是普通字符串密钥,直接使用即可,无需base64转换 // $keyBytes = 'custom_key_here';
3. 完全绕过认证上下文生成Token
如果上述调整后仍有问题,可以直接使用JWT类生成Token,彻底脱离Laravel认证系统的上下文:
use Tymon\JWTAuth\JWT; $jwt = new JWT(); $token = $jwt->encode($payload, $keyBytes, 'HS256');
验证Payload正确性
生成Payload后,直接打印确认字段是否符合预期:
dd($payload->toArray());
正常输出应只包含你设置的sub、exp、iss、aud,无任何用户相关字段。
内容的提问来源于stack exchange,提问作者Thalles Portilho
相关产品推荐
相关产品推荐

