feat(player-auth): add JWT TTL check and AES wrapped token support
1. 新增JWT有效期校验,限制exp-iat最大时长并支持强制校验iat字段 2. 新增AES-GCM密文Token解包能力,支持非标准JWT格式的令牌传递 3. 新增相关配置项和环境变量,可灵活调整校验策略
This commit is contained in:
55
app/Support/PlayerTokenAesUnwrap.php
Normal file
55
app/Support/PlayerTokenAesUnwrap.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
/**
|
||||
* URL/Query 传入的 AES-256-GCM 密文 Token 解包为内层 JWT 明文字符串。
|
||||
*
|
||||
* 约定:Base64( IV(12) ‖ ciphertext ‖ tag(16) ),明文为 UTF-8 JWT(三点分段)。
|
||||
* 密钥:`config('lottery.player_auth.aes.key_base64')` Base64 解码后为 32 字节。
|
||||
*/
|
||||
final class PlayerTokenAesUnwrap
|
||||
{
|
||||
/**
|
||||
* @return 内层 JWT 或 null(未启用/格式错/解密失败)
|
||||
*/
|
||||
public static function tryUnwrap(string $opaque): ?string
|
||||
{
|
||||
$keyB64 = config('lottery.player_auth.aes.key_base64');
|
||||
if (! is_string($keyB64) || trim($keyB64) === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$keyRaw = base64_decode(trim($keyB64), true);
|
||||
if (! is_string($keyRaw) || strlen($keyRaw) !== 32) {
|
||||
return null;
|
||||
}
|
||||
$trim = trim($opaque);
|
||||
if ($trim === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bin = base64_decode(strtr($trim, '-_', '+/'), true);
|
||||
if ($bin === false || strlen($bin) < 12 + 1 + 16) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$iv = substr($bin, 0, 12);
|
||||
$tag = substr($bin, -16);
|
||||
$cipher = substr($bin, 12, -16);
|
||||
|
||||
$plain = openssl_decrypt($cipher, 'aes-256-gcm', $keyRaw, OPENSSL_RAW_DATA, $iv, $tag);
|
||||
if (! is_string($plain) || $plain === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::looksLikeJwt($plain) ? $plain : null;
|
||||
}
|
||||
|
||||
private static function looksLikeJwt(string $s): bool
|
||||
{
|
||||
return preg_match('/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/', $s) === 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user