You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP及CodeIgniter 4中验证JWT令牌是否被篡改?

JWT令牌防篡改验证及PHP/CodeIgniter 4实现方案

JWT本身通过签名机制防止篡改,令牌分为Header、Payload、Signature三段,用.分隔。签名是由Header和Payload的Base64URL编码内容,加上密钥通过指定算法(比如HS256)生成的。只要令牌内容(Header/Payload)被篡改,重新计算的签名就会和原签名不匹配,验证时直接失败。

你遇到的“Wrong number of segments in”错误,是因为篡改后的令牌破坏了JWT的三段式结构(比如删掉了.、新增了多余的分隔符,或者内容编码后格式错乱),导致解析器无法正确拆分出Header、Payload、Signature三段,进而抛出异常。


一、普通PHP中的验证方法

常用第三方库firebase/php-jwt简化验证流程,步骤如下:

  1. 安装库
composer require firebase/php-jwt
  1. 验证代码示例(含异常捕获)
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use UnexpectedValueException;

// 与生成令牌时一致的密钥
$secretKey = 'your-secure-secret-key';

// 用户提供的待验证令牌
$token = 'user-submitted-jwt-token';

try {
    // 自动校验结构、签名、过期时间等
    $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
    
    // 验证通过,$decoded包含解析后的Header和Payload数据
    var_dump($decoded);
} catch (UnexpectedValueException $e) {
    // 捕获结构错误(如segments数量异常)或签名不匹配的情况
    echo '令牌无效:' . $e->getMessage();
} catch (ExpiredException $e) {
    // 单独处理令牌过期场景(可选)
    echo '令牌已过期:' . $e->getMessage();
} catch (\Exception $e) {
    // 其他异常兜底处理
    echo '验证失败:' . $e->getMessage();
}
  • 核心逻辑:JWT::decode()会自动完成结构合法性校验和签名一致性验证,只要令牌被篡改(内容或结构),都会抛出对应异常。

二、CodeIgniter 4中的验证方法

CI4支持两种实现方式:集成第三方库,或使用官方内置JWT组件(CI4.2+版本推荐)。

方式1:集成firebase/php-jwt库

  1. 先按普通PHP步骤安装库
  2. 在CI4控制器或工具类中实现验证:
<?php
namespace App\Controllers;

use CodeIgniter\Controller;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use UnexpectedValueException;

class Auth extends Controller
{
    public function verifyToken()
    {
        // 从配置文件读取密钥(建议存放在app/Config/Auth.php中)
        $secretKey = config('Auth')->jwtSecret;
        $token = $this->request->getHeaderLine('Authorization');
        
        // 提取Bearer格式的令牌(如果请求头用此规范)
        if (strpos($token, 'Bearer ') === 0) {
            $token = substr($token, 7);
        }

        try {
            $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
            
            // 验证通过后,可将用户信息存入请求对象供后续使用
            $this->request->setUserdata(['auth_user' => (array)$decoded]);
            
            return $this->response->setJSON(['status' => 'success', 'data' => $decoded]);
        } catch (UnexpectedValueException $e) {
            return $this->response->setJSON(['status' => 'error', 'message' => '令牌无效:' . $e->getMessage()])->setStatusCode(401);
        } catch (\Exception $e) {
            return $this->response->setJSON(['status' => 'error', 'message' => '验证失败:' . $e->getMessage()])->setStatusCode(401);
        }
    }
}

方式2:使用CI4官方JWT组件(推荐)

CI4.2+内置JWT支持,无需额外安装第三方库:

  1. 配置密钥:在app/Config/Auth.php中设置$secretKey(对称算法用)或$publicKey/$privateKey(非对称算法用)
  2. 验证代码示例:
<?php
namespace App\Controllers;

use CodeIgniter\Controller;
use CodeIgniter\Authentication\JWT\JWT;
use CodeIgniter\Authentication\JWT\Exceptions\JWTException;

class Auth extends Controller
{
    public function verifyToken()
    {
        $token = $this->request->getHeaderLine('Authorization');
        
        if (strpos($token, 'Bearer ') === 0) {
            $token = substr($token, 7);
        }

        try {
            $decoded = JWT::verify($token, config('Auth')->secretKey, 'HS256');
            
            return $this->response->setJSON(['status' => 'success', 'data' => $decoded]);
        } catch (JWTException $e) {
            return $this->response->setJSON(['status' => 'error', 'message' => $e->getMessage()])->setStatusCode(401);
        }
    }
}
  • 进阶优化:可以通过CI4的Filters实现全局令牌验证,在app/Config/Filters.php中注册过滤器后,直接在路由中应用,避免重复编写验证逻辑。

内容的提问来源于stack exchange,提问作者Sambit Swagatam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:20:06