概述
JSON Web Token(JWT)是一种轻量级的身份认证方案,适用于前后端分离架构中的身份校验场景。本文基于 Yii2 框架,介绍 JWT 的引入、代码实现、校验流程及安全防护措施,以快速集成 JWT。
环境准备:引入 JWT 组件
通过 Composer 快速安装 Firebase 提供的 PHP-JWT 组件,该组件兼容主流 PHP 版本,且集成简单、性能稳定。
composer require firebase/php-jwt
代码实现
以下代码实现了用户登录生成 Token、身份校验两大核心功能,可根据实际业务需求调整用户信息字段、过期时间等配置。
完整代码示例
<?php
declare(strict_types = 1);
namespace app\controllers;
use app\common\Helper;
use Firebase\JWT\JWT;
use yii\base\Controller;
class TestController extends Controller
{
/**
* 登录接口:验证身份并生成 JWT Token
* @throws \Exception
*/
public function actionLogin()
{
// 1. 实际场景需替换为真实的验证码、用户名密码校验逻辑
$isValid = true; // 校验结果(true 为通过,false 为失败)
if (!$isValid) {
return Helper::msg(0, '登录失败,验证码、用户名或密码错误');
}
// 2. 校验通过后,获取数据库中的用户信息(示例数据)
$userInfo = [
'user_id' => 10000, // 用户唯一ID
'user_name' => 'haveyb', // 用户名
'is_admin' => 1, // 是否为管理员(1=是,0=否)
'menus' => [1, 2, 6, 13], // 用户权限菜单ID集合
];
// 3. 生成 JWT Token(用于后续接口身份校验)
$token = $this->generateJwtToken($userInfo);
// 4. 返回给前端的响应数据
$responseData = [
'user_id' => $userInfo['user_id'],
'user_name' => $userInfo['user_name'],
'menus' => $userInfo['menus'],
'token' => $token // 核心 Token 字段
];
return Helper::msg(1, '登录成功', $responseData);
}
/**
* 身份校验接口:验证 Token 有效性并返回用户信息
* 实际场景中可被其他需要权限校验的接口调用
*/
public function actionCheckAuth()
{
// 1. 获取前端传递的 Token(推荐放在请求头 Header 或 Cookie 中)
$requestToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvd3d3LmhhdmV5Yi5jb20iLCJjcmVhdGVfdGltZSI6MTU4NjMzMzAwMSwidXNlcl9pZCI6MTAwMDAsImlzX2FkbWluIjoxfQ.VrGWf6nfhy8g5f-MufZK7J_OnOkUKiVHp4p9E9JavQw';
// 2. 配置 JWT 密钥和加密算法(与生成 Token 时保持一致)
$secretKey = $this->getJwtSecret();
$algorithm = $this->getJwtAlgorithm();
try {
// 3. 验证 Token 签名有效性(抛出异常则说明 Token 被篡改或无效)
$decodedData = (array)JWT::decode($requestToken, $secretKey, [$algorithm]);
} catch (\Exception $e) {
return Helper::msg(0, '身份校验失败:无效的 Token');
}
// 4. 校验 Token 过期时间(推荐必加,防止永久有效 Token 泄露风险)
$expireTime = 86400; // 过期时间:24小时(单位:秒)
if (time() - $decodedData['create_time'] > $expireTime) {
return Helper::msg(0, '身份校验失败:Token 已过期,请重新登录');
}
// 5. 校验通过,返回用户身份信息(可进一步关联数据库查询最新用户数据)
return Helper::msg(1, '身份校验成功', $decodedData);
}
/**
* 生成 JWT Token 核心方法
* @param array $userInfo 用户信息数组
* @return string 生成的 Token 字符串
*/
private function generateJwtToken(array $userInfo): string
{
$secretKey = $this->getJwtSecret();
$algorithm = $this->getJwtAlgorithm();
$currentTime = time();
// Token 载荷(Payload):存储核心业务数据(避免敏感信息)
$payload = [
'iss' => 'https://www.haveyb.com', // 签发者(通常为项目域名)
'create_time' => $currentTime, // Token 创建时间(时间戳)
'user_id' => $userInfo['user_id'], // 用户ID(核心标识)
'is_admin' => $userInfo['is_admin']// 管理员标识(权限控制)
];
// 生成并返回 Token
return JWT::encode($payload, $secretKey, $algorithm);
}
/**
* 获取 JWT 加密密钥(核心安全配置)
* @return string 密钥字符串(建议通过环境变量存储,避免硬编码)
*/
private function getJwtSecret(): string
{
// 示例密钥:建议替换为随机生成的32位以上字符串(如通过 openssl_random_pseudo_bytes 生成)
return 'BQXSD0PxCFPN/3xa06/94PWm++0ZKOHw83kP0=';
}
/**
* 获取 JWT 加密算法
* @return string 算法名称(HS256 为 HMAC-SHA256,适用于对称加密场景)
*/
private function getJwtAlgorithm(): string
{
return 'HS256'; // 对称加密算法,高效且易于实现(非对称加密可选用 RS256)
}
}
代码关键说明
-
载荷(Payload)设计:存储非敏感核心数据(如用户ID、权限标识),避免存储密码、手机号等敏感信息;
-
密钥安全:
getJwtSecret()方法返回的密钥是 Token 安全的核心,切勿泄露或硬编码在前端; -
加密算法:HS256 为对称加密算法,前后端使用同一密钥;若需分布式部署或多服务协作,可选用 RS256 非对称加密;
-
过期时间:默认 24 小时过期,可根据业务需求调整(如后台管理系统可缩短至 1 小时)。
使用流程与校验结果
1. 登录获取 Token
-
前端调用
actionLogin()接口,传递用户名、密码、验证码等参数; -
后端校验通过后,返回包含 Token 的响应数据;
-
前端存储 Token(如 localStorage、Cookie),用于后续接口请求。
2. 接口身份校验
-
前端请求需要权限的接口时,在请求头(如
Authorization: Bearer {Token})中携带 Token; -
后端接口调用
actionCheckAuth()方法,校验 Token 有效性; -
校验通过则继续业务逻辑,失败则返回错误信息(如 Token 过期、无效),要求用户重新登录。
3. 校验结果说明
-
成功:返回状态码 1 及用户身份信息,允许接口访问;
-
失败:返回状态码 0 及错误提示(如 Token 无效、过期),阻断接口访问。
五、安全防护措施
JWT Token 一旦泄露,攻击者可伪造用户身份操作,因此必须做好以下安全防护:
1. 强制使用 HTTPS 协议
-
基于 SSL/TLS 加密传输,防止 Token 在网络传输过程中被窃听或篡改;
-
部署时需配置有效的 SSL 证书(如 Let's Encrypt 免费证书)。
2. 强化密钥安全性
-
密钥长度不少于 32 位,可通过
openssl_random_pseudo_bytes(32)生成随机字符串; -
密钥通过环境变量(如
.env文件)或配置中心存储,避免硬编码在代码中。
3. 严格校验 Token 过期时间
-
必须添加过期时间校验(如示例中的 24 小时),缩短 Token 有效窗口;
-
对于高安全性场景(如支付、后台管理),可设置更短的过期时间(如 30 分钟),并结合刷新 Token 机制。
4. 可选:添加 IP 绑定校验
-
生成 Token 时,在载荷中添加用户 IP 字段(
user_ip=> $_SERVER['REMOTE_ADDR']); -
校验 Token 时,对比当前请求 IP 与载荷中的 IP,不一致则拒绝访问;
-
注意:动态 IP 场景(如手机流量)不适用,需谨慎使用。
5. 其他补充防护
-
避免在 Token 中存储敏感信息(如密码、身份证号);
-
前端避免将 Token 存储在 localStorage(易受 XSS 攻击),优先使用 HttpOnly + Secure Cookie;
-
定期更换密钥(需处理旧 Token 兼容问题,如设置过渡期)。
六、扩展建议
-
刷新 Token 机制:为避免用户频繁登录,可生成访问 Token(短期有效)和刷新 Token(长期有效),访问 Token 过期后,通过刷新 Token 重新获取;
-
分布式部署支持:若系统为分布式部署,使用 RS256 非对称加密算法,避免密钥同步问题;
-
日志记录:记录 Token 生成、校验失败等关键操作,便于排查安全问题;
-
权限细化:结合 Token 中的权限标识(如
is_admin、menus),实现接口级别的权限控制。


