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

使用firebase/php-jwt生成刷新令牌及过期后重验证的实现方法

基于firebase/php-jwt的Refresh Token实现方案

一、Refresh Token下发逻辑

Refresh Token和短有效期的Access Token配套使用,核心作用是避免用户频繁输入账号密码登录,前者有效期通常设为730天,后者设为1530分钟。下发逻辑如下:

  • 首先确认你使用的Refresh Token方案,两类方案可选:
    1. 有状态方案(生产环境推荐):用bin2hex(random_bytes(32))生成64位随机唯一字符串作为Refresh Token,将该字符串、对应用户ID、过期时间、设备标识(可选)存储到数据库/Redis中,无需封装为JWT格式。
    2. 无状态方案:直接用JWT签发Refresh Token,和Access Token使用不同的签名密钥,Payload仅存储用户ID这类基础信息,不要存储权限等敏感字段。
  • 下发时机:用户登录验证账号密码通过后,和Access Token同时返回给客户端,返回字段一般包含access_token、refresh_token、expires_in(Access Token的有效秒数)。

生产环境优先选择有状态的Refresh Token方案,可满足主动作废、限制多设备登录、被盗后快速冻结等安全需求。

二、令牌刷新逻辑

客户端检测到Access Token即将过期时,调用服务端刷新接口,携带Refresh Token请求新的Access Token,服务端验证逻辑如下:

有状态Refresh Token验证步骤

  • 取客户端传入的Refresh Token,到存储层查询是否存在对应记录
  • 检查记录的过期时间,如果已过期直接返回验证失败
  • 验证记录绑定的用户状态正常,无封禁、注销等情况
  • 验证通过后生成新的Access Token,同时可生成新的Refresh Token实现滑动有效期,将旧Refresh Token标记为失效后,返回新的双Token给客户端

无状态JWT格式Refresh Token验证步骤

  • 用专属的Refresh Token签名密钥解密JWT,验证签名合法性
  • 校验过期时间,过期直接返回验证失败
  • 取出Payload中的用户ID,验证用户状态正常
  • 生成新的Access Token返回,如需滑动有效期则同步签发新的Refresh Token返回

三、Refresh Token过期后的重验证机制

  • 只要Refresh Token验证不通过(过期、不存在、已作废、签名错误),服务端统一返回401 Unauthorized状态码,可搭配自定义业务码标识登录失效
  • 客户端收到对应状态码/业务码后,直接清空本地存储的所有Token,跳转至登录页面,要求用户重新输入账号密码完成身份校验
  • 可选安全增强:同一个Refresh Token仅允许使用一次,每次刷新就生成新的Token,若收到已使用过的Refresh Token的刷新请求,直接作废该用户所有生效的Refresh Token,强制用户重新登录,降低Token盗用风险

简易代码示例

双Token下发代码

// 初始化配置
$accessSecret = '你的Access Token专属签名密钥';
$refreshSecret = '你的Refresh Token专属签名密钥';
$accessExp = 15 * 60; // Access Token有效期15分钟
$refreshExp = 7 * 24 * 3600; // Refresh Token有效期7天

// 账号密码验证通过后拿到用户ID
$userId = 10001;

// 签发Access Token
$accessPayload = [
    'iss' => '你的服务标识',
    'iat' => time(),
    'exp' => time() + $accessExp,
    'uid' => $userId,
    'role' => '普通用户'
];
$accessToken = Firebase\JWT\JWT::encode($accessPayload, $accessSecret, 'HS256');

// 签发无状态Refresh Token
$refreshPayload = [
    'iss' => '你的服务标识',
    'iat' => time(),
    'exp' => time() + $refreshExp,
    'uid' => $userId
];
$refreshToken = Firebase\JWT\JWT::encode($refreshPayload, $refreshSecret, 'HS256');

// 返回给客户端
echo json_encode([
    'access_token' => $accessToken,
    'refresh_token' => $refreshToken,
    'expires_in' => $accessExp
]);

刷新接口代码

try {
    $clientRefreshToken = $_POST['refresh_token'];
    // 验证Refresh Token合法性
    $decoded = Firebase\JWT\JWT::decode($clientRefreshToken, new Firebase\JWT\Key($refreshSecret, 'HS256'));
    $userId = $decoded->uid;
    
    // 此处省略用户状态合法性校验逻辑
    
    // 生成新的Access Token
    $newAccessPayload = [
        'iss' => '你的服务标识',
        'iat' => time(),
        'exp' => time() + $accessExp,
        'uid' => $userId,
        'role' => '普通用户'
    ];
    $newAccessToken = Firebase\JWT\JWT::encode($newAccessPayload, $accessSecret, 'HS256');
    
    // 可选生成新的Refresh Token实现滑动有效期
    $newRefreshPayload = [
        'iss' => '你的服务标识',
        'iat' => time(),
        'exp' => time() + $refreshExp,
        'uid' => $userId
    ];
    $newRefreshToken = Firebase\JWT\JWT::encode($newRefreshPayload, $refreshSecret, 'HS256');

    // 返回新Token
    echo json_encode([
        'access_token' => $newAccessToken,
        'refresh_token' => $newRefreshToken,
        'expires_in' => $accessExp
    ]);
} catch (Firebase\JWT\ExpiredException $e) {
    // Refresh Token过期
    http_response_code(401);
    echo json_encode(['code' => 10010, 'msg' => '登录状态已过期,请重新登录']);
} catch (Exception $e) {
    // 其他验证失败
    http_response_code(401);
    echo json_encode(['code' => 10010, 'msg' => '登录状态无效,请重新登录']);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 02:15:07