PHP如何实现JWT鉴权及token生成与刷新过期机制

来源:IPIPP.com作者:梦乃头衔:网络博主
导读:本期聚焦于小伙伴创作的《PHP如何实现JWT鉴权及token生成与刷新过期机制》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PHP如何实现JWT鉴权及token生成与刷新过期机制》有用,将其分享出去将是对创作者最好的鼓励。

JWT即JSON Web Token,是目前前后端分离场景下主流的身份鉴权方案,通过加密签名生成的token可以在服务端无状态的情况下完成用户身份验证,相比传统的session方案更适合分布式系统部署。

PHP如何实现JWT鉴权及token生成与刷新过期机制

JWT的基本结构

一个标准的JWT字符串由三部分组成,分别是头部Header、载荷Payload、签名Signature,三部分之间用点号分隔。Header主要存放签名算法和token类型,Payload存放需要传递的用户信息和过期时间等数据,Signature是对前两部分的加密签名,用于校验token是否被篡改。

PHP生成JWT token的实现

生成JWT的核心步骤是先构造Header和Payload的JSON字符串,然后进行Base64Url编码,再使用指定的签名算法对前两部分拼接后的内容进行签名,最后拼接成完整的token字符串。下面是具体的实现代码:

<?php
class JwtService {
    // 签名密钥,实际生产环境需要妥善保管,不要硬编码在代码中
    private $secret = 'your_jwt_secret_key_2024';
    // 签名算法,这里使用HS256
    private $alg = 'HS256';

    /**
     * 生成JWT token
     * @param array $payload 载荷数据,需要包含用户标识等信息
     * @param int $expire 过期时间,单位秒,默认3600秒即1小时
     * @return string 生成的JWT token
     */
    public function generateToken($payload, $expire = 3600) {
        // 构造Header
        $header = [
            'alg' => $this->alg,
            'typ' => 'JWT'
        ];
        // 给Payload添加过期时间和签发时间
        $payload['iat'] = time();
        $payload['exp'] = time() + $expire;
        // 对Header和Payload进行Base64Url编码
        $base64Header = $this->base64UrlEncode(json_encode($header, JSON_UNESCAPED_UNICODE));
        $base64Payload = $this->base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
        // 生成签名
        $signature = $this->generateSignature($base64Header, $base64Payload);
        // 拼接成完整的JWT token
        return $base64Header . '.' . $base64Payload . '.' . $signature;
    }

    /**
     * Base64Url编码,替换标准Base64中的+和/,去掉末尾的=
     * @param string $data 需要编码的数据
     * @return string 编码后的字符串
     */
    private function base64UrlEncode($data) {
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
    }

    /**
     * 生成签名
     * @param string $base64Header 编码后的Header
     * @param string $base64Payload 编码后的Payload
     * @return string 签名字符串
     */
    private function generateSignature($base64Header, $base64Payload) {
        $content = $base64Header . '.' . $base64Payload;
        if ($this->alg == 'HS256') {
            $signature = hash_hmac('sha256', $content, $this->secret, true);
        } else {
            // 可以扩展其他签名算法
            throw new Exception('不支持的签名算法');
        }
        return $this->base64UrlEncode($signature);
    }
}

// 使用示例
$jwtService = new JwtService();
// 载荷中存放用户ID和用户名
$payload = [
    'user_id' => 1001,
    'username' => 'test_user'
];
// 生成1小时过期的token
$token = $jwtService->generateToken($payload, 3600);
echo '生成的token:' . $token;
?>

JWT token的校验与过期处理

服务端接收到客户端传递的token后,需要先拆分token的三部分,然后校验签名是否正确,再检查过期时间是否过期。如果签名错误说明token被篡改,直接拒绝请求;如果已经过期则需要根据刷新机制处理。

下面是token校验的实现代码:

<?php
class JwtService {
    // 之前的属性和方法省略,这里补充校验相关方法
    private $secret = 'your_jwt_secret_key_2024';
    private $alg = 'HS256';

    // 之前的base64UrlEncode、generateSignature方法省略

    /**
     * 校验JWT token
     * @param string $token 需要校验的token
     * @return array 校验结果,包含status和data字段
     */
    public function verifyToken($token) {
        // 拆分token
        $parts = explode('.', $token);
        if (count($parts) != 3) {
            return ['status' => false, 'msg' => 'token格式错误'];
        }
        list($base64Header, $base64Payload, $signature) = $parts;
        // 校验签名
        $expectedSignature = $this->generateSignature($base64Header, $base64Payload);
        if ($signature != $expectedSignature) {
            return ['status' => false, 'msg' => 'token签名错误,可能被篡改'];
        }
        // 解析Payload
        $payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $base64Payload)), true);
        if (!$payload) {
            return ['status' => false, 'msg' => 'token载荷解析失败'];
        }
        // 检查是否过期
        if (isset($payload['exp']) && $payload['exp'] < time()) {
            return ['status' => false, 'msg' => 'token已过期', 'code' => 401001];
        }
        return ['status' => true, 'data' => $payload];
    }
}

// 使用示例
$jwtService = new JwtService();
// 假设从请求头中获取到的token
$clientToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMDAxLCJ1c2VybmFtZSI6InRlc3RfdXNlciIsImlhdCI6MTY5MDAwMDAwMCwiZXhwIjoxNjkwMDAzNjAwfQ.abc123';
$result = $jwtService->verifyToken($clientToken);
if ($result['status']) {
    echo 'token校验通过,用户信息:' . json_encode($result['data']);
} else {
    echo 'token校验失败:' . $result['msg'];
}
?>

token刷新机制的实现

为了避免用户频繁登录,通常会设置两个过期时间:access_token的短期过期时间(比如1小时)和refresh_token的长期过期时间(比如7天)。当access_token过期时,客户端携带refresh_token请求刷新接口,服务端校验refresh_token有效后,生成新的access_token返回给客户端。

实现刷新机制需要注意几个要点:refresh_token需要单独存储,比如存放在服务端的缓存或者数据库中,避免被盗用;refresh_token过期后需要用户重新登录;刷新token的操作需要校验客户端身份,避免恶意刷新。

下面是刷新token的示例代码:

<?php
class JwtService {
    // 之前的属性和方法省略
    private $secret = 'your_jwt_secret_key_2024';
    private $alg = 'HS256';

    // 假设这里有一个存储refresh_token的数组,实际生产环境用Redis或数据库存储
    private $refreshTokenStore = [];

    /**
     * 生成refresh_token并存储
     * @param int $userId 用户ID
     * @param int $expire refresh_token过期时间,默认7天
     * @return string refresh_token
     */
    public function generateRefreshToken($userId, $expire = 604800) {
        $refreshToken = bin2hex(random_bytes(32));
        $this->refreshTokenStore[$refreshToken] = [
            'user_id' => $userId,
            'exp' => time() + $expire
        ];
        return $refreshToken;
    }

    /**
     * 刷新access_token
     * @param string $refreshToken 客户端传递的refresh_token
     * @return array 刷新结果
     */
    public function refreshAccessToken($refreshToken) {
        // 校验refresh_token是否存在且未过期
        if (!isset($this->refreshTokenStore[$refreshToken])) {
            return ['status' => false, 'msg' => 'refresh_token不存在'];
        }
        $tokenInfo = $this->refreshTokenStore[$refreshToken];
        if ($tokenInfo['exp'] < time()) {
            unset($this->refreshTokenStore[$refreshToken]);
            return ['status' => false, 'msg' => 'refresh_token已过期,请重新登录'];
        }
        // 生成新的access_token
        $payload = [
            'user_id' => $tokenInfo['user_id']
        ];
        $newAccessToken = $this->generateToken($payload, 3600);
        return ['status' => true, 'access_token' => $newAccessToken];
    }
}

// 使用示例
$jwtService = new JwtService();
// 用户登录成功后生成access_token和refresh_token
$userId = 1001;
$accessToken = $jwtService->generateToken(['user_id' => $userId], 3600);
$refreshToken = $jwtService->generateRefreshToken($userId, 604800);
echo '登录成功,access_token:' . $accessToken . ',refresh_token:' . $refreshToken;

// 当access_token过期时,调用刷新接口
$refreshResult = $jwtService->refreshAccessToken($refreshToken);
if ($refreshResult['status']) {
    echo '刷新成功,新的access_token:' . $refreshResult['access_token'];
} else {
    echo '刷新失败:' . $refreshResult['msg'];
}
?>

注意事项

  • JWT的密钥需要妥善保管,不要泄露给客户端,否则攻击者可以伪造token。
  • 不要在JWT的Payload中存放敏感信息,因为Payload只是Base64编码,不是加密,任何人都可以解码查看内容。
  • token的过期时间不要设置过长,access_token建议设置1小时以内,refresh_token建议设置7天以内,降低被盗用的风险。
  • 如果需要让已经签发的token立即失效,比如用户修改密码或者退出登录,需要维护一个黑名单,校验token时先检查是否在黑名单中,不过这会增加服务端的存储成本,需要根据实际场景选择。

以上就是PHP实现JWT鉴权、token生成与刷新过期机制的完整方案,开发者可以根据自己的业务需求调整签名算法、过期时间和存储方式,搭建适合自己项目的鉴权体系。

PHPJWTtoken生成token刷新过期机制修改时间:2026-07-12 02:42:41

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。