CodeIgniter 4 需手动集成 firebase/php-jwt 实现 JWT,关键在于正确配置自动加载、统一管理密钥、规范 payload 结构、使用过滤器全局验证 token,并注意时间同步、算法匹配与 HTTPS 安全传输。

CodeIgniter 4 本身不带 JWT 支持,必须用 firebase/php-jwt 手动集成;不是“能不能加”,而是“你愿不愿意承担 token 管理的复杂度”——比如密钥轮换、黑名单维护、时间同步校验。
安装 firebase/php-jwt 并配置自动加载
直接运行 composer require firebase/php-jwt 即可。别手动 require 类文件,CI4 的 autoloader 会失效。
在 app/Config/Autoload.php 的 $psr4 数组里补上命名空间映射(推荐,避免后续类找不到):
$psr4 = [
'App\' => APPPATH,
'Firebase\JWT' => ROOTPATH . 'vendor/firebase/php-jwt/src/',
];
- 漏配会导致
Class "FirebaseJWTJWT" not found错误 - 不要把密钥写死在控制器里,应统一放在
app/Config/JWT.php中(新建该文件) - CI4 的
Time::now()->addHours(1)->getTimestamp()返回的是CodeIgniterI18nTime对象,不能直接塞进exp字段——必须用(int) time() + 3600
登录接口生成 token:payload 和签名必须匹配算法
核心是三件事:查用户、构造 payload、用私钥签名。其中最容易出错的是 JWT::encode() 的第三个参数。
示例片段(注意类型和顺序):
$payload = [
'user_id' => $user['id'],
'exp' => (int) time() + 3600,
'iat' => (int) time(),
'iss' => 'my-api',
];
$token = FirebaseJWTJWT::encode($payload, config('JWT')->secret, 'HS256');
- 漏传第 3 个参数(如
'HS256'),decode()时会抛DomainException: Signature verification failed -
exp和iat必须是整数,不是字符串或对象 - 不要在 payload 里放密码、手机号、邮箱等敏感字段——Base64Url 可解码,不是加密
用 Filter 实现全局 token 验证
CI4 的过滤器机制比手写中间件更干净,适合统一拦截未认证请求。
在 app/Filters/TokenFilter.php 中实现验证逻辑,关键点是捕获并解析 Authorization: Bearer <token> 头:
public function before(RequestInterface $request, $arguments = null)
{
$authHeader = $request->getServer('HTTP_AUTHORIZATION');
if (!$authHeader || strpos($authHeader, 'Bearer ') !== 0) {
throw new CodeIgniterExceptionsForbiddenException('Missing or invalid Authorization header');
}
$token = substr($authHeader, 7);
try {
$decoded = FirebaseJWTJWT::decode($token, config('JWT')->secret, ['HS256']);
// 把用户 ID 挂到服务容器,供后续控制器使用
service('session')->set('user_id', $decoded->user_id);
} catch (FirebaseJWTExpiredException $e) {
throw new CodeIgniterExceptionsForbiddenException('Token expired');
} catch (Exception $e) {
throw new CodeIgniterExceptionsForbiddenException('Invalid token');
}
}
- 别在
before()里做数据库查询——JWT 本意就是无状态,验签不查库 - 如果需要支持 token 注销,得额外维护一个 Redis 黑名单,且每次
decode()前先查一次 - 生产环境务必启用 HTTPS,否则
Authorization头可能被中间人截获
JWT::decode() 报错常见原因与绕过陷阱
实际部署中最常卡在这一步,错误信息往往含糊,但根源就几个:
-
Signature verification failed:密钥不一致(开发环境用.env覆盖了密钥但没生效)、算法名拼错(比如写成hs256小写)、header 里声明的alg和 decode 时传入的不匹配 -
Expired token:服务器时间不准,和客户端差太多;或者exp写成了字符串"1715584560",PHP 自动转成 int 后可能溢出 -
Invalid token:token 被前端截断(比如 URL 里没处理好+或/字符)、base64url 解码失败 - 别依赖
$_SERVER['HTTP_AUTHORIZATION']—— Apache 下可能为空,要用$request->getServer('HTTP_AUTHORIZATION')或兼容写法
真正麻烦的不是生成 token,而是让每个环节都对齐:时间、编码、密钥、算法、传输头格式。少一个对齐点,整个链路就断在 decode() 上。


















