harry / think-jwt
JSON Web Token (JWT) for ThinkPHP plugin
0.1.0
2026-08-27 00:28 UTC
Requires
- php: ^8.4
- firebase/php-jwt: ^7.1
Requires (Dev)
- topthink/framework: ^8.1.4
README
基于 PHP 8.4 重构的 ThinkPHP JWT 认证组件,采用现代 PHP 特性与领域驱动设计。
架构概览
src/
├── JWT.php # 门面入口
├── RedisHandler # Redis 兼容层
├── Enum/
│ └── TokenType.php # 令牌类型枚举
├── DTO/
│ ├── JWTConfig.php # 配置只读对象
│ └── TokenPayload.php # 载荷数据对象
├── Contract/
│ └── TokenStorageInterface.php # 存储接口
├── Storage/
│ └── RedisTokenStorage.php # Redis 存储实现
├── Service/
│ ├── TokenFactory.php # 令牌工厂
│ └── TokenValidator.php # 令牌验证器
├── Exception/ # 异常体系
└── config.php # 默认配置
设计模式
| 模式 | 应用 |
|---|---|
| 门面模式 | JWT 类提供统一静态入口 |
| 工厂模式 | TokenFactory 负责创建令牌对 |
| 策略模式 | TokenStorageInterface 解耦存储实现 |
| DTO 模式 | JWTConfig / TokenPayload 只读数据对象 |
| 枚举 | TokenType 替代类常量 |
安装
composer require harry/think-jwt
配置
发布配置文件到 config/jwt.php:
return [ 'algorithms' => 'HS256', 'access_secret_key' => 'your-access-secret', 'refresh_secret_key' => 'your-refresh-secret', 'access_exp' => 7200, // 2 小时 'refresh_exp' => 604800, // 7 天 'iss' => 'your-app.com', 'single_device' => false, 'refresh_is_store' => false, 'user_model' => fn(int $uid) => User::find($uid)?->toArray(), ];
使用
生成令牌
use harry\JWT; use harry\Enum\TokenType; $user = ['id' => 2026, 'name' => 'Harry', 'email' => 'harry@163.com']; $token = JWT::generateToken($user); // 返回 // [ // 'token_type' => 'Bearer', // 'expires_in' => 7200, // 'access_token' => 'eyJ...', // 'refresh_token' => 'eyJ...', // ]
验证令牌
use harry\JWT; use harry\Enum\TokenType; /** @var \harry\DTO\TokenPayload $payload */ $payload = JWT::verify(TokenType::Access); echo $payload->userId(); // 用户ID echo $payload->claim('name'); // 自定义字段 echo $payload->expiresAt; // 过期时间戳
从请求头验证
// 自动从 Authorization 头解析 Bearer 令牌 $payload = JWT::verify();
刷新令牌
$newToken = JWT::refreshToken(); // ['access_token' => 'eyJ...']
获取当前用户信息
$uid = JWT::getCurrentId(); $role = JWT::getCurrentRoleCode(); $allClaims = JWT::getExtend(); $email = JWT::getExtendVal('email'); $user = JWT::getUser(); // 通过 user_model 回调获取
删除刷新令牌
JWT::deleteRefreshToken('2026');
API 速查
| 方法 | 说明 |
|---|---|
JWT::generateToken(array $claims) |
生成令牌对 |
JWT::verify(?TokenType $type, ?string $token) |
验证令牌,返回 TokenPayload |
JWT::refreshToken() |
刷新 Access 令牌 |
JWT::getCurrentId() |
获取当前用户ID |
JWT::getCurrentRoleCode() |
获取角色code |
JWT::getCurrentRoleId() |
获取角色ID |
JWT::getUser() |
获取用户信息(通过模型回调) |
JWT::getExtend() |
获取所有扩展字段 |
JWT::getExtendVal(string $key) |
获取指定扩展字段 |
JWT::getTokenExp(?TokenType $type) |
获取剩余有效期(秒) |
JWT::deleteRefreshToken(string $userId) |
删除刷新令牌 |
高级用法
自定义配置注入
use harry\JWT; use harry\DTO\JWTConfig; $config = new JWTConfig( algorithms: 'RS256', accessPrivateKey: file_get_contents('/path/to/private.pem'), accessPublicKey: file_get_contents('/path/to/public.pem'), accessTtl: 3600, ); JWT::configure($config);
自定义存储实现
use harry\Contract\TokenStorageInterface; class DatabaseTokenStorage implements TokenStorageInterface { public function store(string $key, string $token, int $ttl): bool { /* ... */ } public function retrieve(string $key): ?string { /* ... */ } public function delete(string $key): bool { /* ... */ } public function exists(string $key): bool { /* ... */ } }
直接使用服务层
use harry\Service\TokenFactory; use harry\Service\TokenValidator; use harry\Storage\RedisTokenStorage; use harry\DTO\JWTConfig; $config = JWTConfig::fromArray(config('jwt')); $storage = new RedisTokenStorage(); $factory = new TokenFactory($config, $storage); $tokens = $factory->pair(['id' => '2026', 'role' => 'admin']); $validator = new TokenValidator($config, $storage); $payload = $validator->verify($tokens['access_token'], TokenType::Access);
签名算法
| 算法 | 类型 | 说明 |
|---|---|---|
| HS256 / HS384 / HS512 | 对称 | 同一密钥签名验证 |
| RS256 / RS384 / RS512 | 非对称 | RSA 私钥签名,公钥验证 |
| ES256 / ES384 / ES512 | 非对称 | ECDSA 签名 |
| Ed25519 | 非对称 | EdDSA 签名(需 sodium 扩展) |
生成 RSA 密钥对
ssh-keygen -t rsa -b 4096 -E SHA256 -m PEM -P "" -f rs256.key
openssl rsa -in rs256.key -pubout -outform PEM -out rs256.key.pub
异常体系
RuntimeException
├── JWTTokenException # 通用令牌异常
│ ├── JWTTokenExpiredException # 令牌已过期
│ └── JWTRefreshTokenExpiredException # 刷新令牌过期
│ └── JWTStoreRefreshTokenExpiredException # 存储的刷新令牌过期
└── JWTConfigException # 配置异常
安全性建议
- 密钥管理:生产环境使用 RS256 非对称算法,私钥妥善保管
- HTTPS 传输:始终通过 HTTPS 传输令牌
- 令牌过期:设置合理的过期时间,Access 令牌建议 ≤ 2 小时
- 刷新令牌存储:开启
refresh_is_store实现令牌吊销 - 单设备登录:开启
single_device防止多设备同时在线 - 时序安全:使用
hash_equals比较令牌,防止计时攻击
要求
- PHP >= 8.4
- topthink/framework >= 8.1.4
- firebase/php-jwt >= 7.1
- ext-redis(可选,用于 Redis 存储)
License
MIT