PHP code example of kode / jwt

1. Go to this page and download the library: Download kode/jwt library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

kode / jwt example snippets




declare(strict_types=1);

/**
 * JWT 配置文件
 * 由 kode/jwt CLI 工具生成
 *
 * @generated_at 2025-12-30 09:14:47
 */

return [
    /**
     * 默认配置
     */
    'defaults' => [
        'guard' => 'api',         // 默认守卫名称
        'provider' => 'users',    // 默认用户提供者
        'platform' => 'web',      // 默认平台
    ],

    /**
     * 守卫配置
     * 每个守卫对应一种认证策略
     */
    'guards' => [
        'api' => [
            'driver' => 'kode',           // 驱动类型(固定为 kode)
            'provider' => 'users',        // 用户提供者
            'storage' => 'redis',         // 存储驱动:redis, memory, null
            'blacklist_enabled' => true,  // 是否启用黑名单
            'refresh_enabled' => true,    // 是否支持自动续期
            'refresh_ttl' => 20160,       // 续期窗口(分钟,默认2周)
            'ttl' => 1440,                // Token 有效期(分钟,默认24小时)
            'algo' => 'RS256',            // 加密算法:RS256, HS256
            'secret' => null,             // HMAC 密钥(RS256 可为 null)
            'public_key' => null,         // RSA 公钥路径或内容
            'private_key' => null,        // RSA 私钥路径或内容
        ],
    ],

    /**
     * 平台配置
     * 用于多平台 Token 隔离
     */
    'platforms' => [
        'web' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'h5' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'pc' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'app' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'wx_mini' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'ali_mini' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
        'tt_mini' => [
            'enabled' => true,
            'guard' => 'api',
            'ttl' => 1440,
        ],
    ],

    /**
     * SSO 配置
     * 单点登录:同一用户在同一平台仅允许一个有效 Token
     */
    'sso' => [
        'enabled' => false,              // 是否启用 SSO
        'scope' => 'platform',           // 隔离范围:platform(平台级), guard(守卫级)
    ],

    /**
     * MLO 配置
     * 多点登录:支持同一用户多个设备同时在线
     */
    'mlo' => [
        'enabled' => false,              // 是否启用 MLO
        'max_devices' => 5,              // 最大设备数
        'kick_old' => false,             // 是否踢掉旧设备
    ],

    /**
     * 存储配置
     */
    'storage' => [
        'redis' => [
            'connection' => 'default',   // Redis 连接名称
            'prefix' => 'kode:jwt:',     // Key 前缀
        ],
        'memory' => [
            'limit' => 10000,            // 最大缓存数量
        ],
    ],

    /**
     * 事件配置
     */
    'events' => [
        'enabled' => true,
        'listeners' => [
            // \App\Listeners\OnTokenIssued::class,
            // \App\Listeners\OnTokenRevoked::class,
        ],
    ],
];

namespace Kode\Jwt\Token;

use Kode\Jwt\Contract\Arrayable;

final readonly class Payload implements Arrayable
{
    public function __construct(
        public int|string|null $uid = null,
        public ?string $username = null,
        public string $platform,
        public int $exp,
        public int $iat,
        public string $jti,
        public ?array $roles = null,
        public ?array $perms = null,
        public array $custom = []
    ) {}

    public function toArray(): array
    {
        return get_object_vars($this);
    }
    
    /**
     * 从数组创建Payload实例
     * 
     * @param array $data 包含Payload数据的数组
     * @return static
     * @throws \InvalidArgumentException 当必需字段缺失时抛出异常
     */
    public static function fromArray(array $data): static
    {
        // 验证必需字段
        $@param string $platform 平台标识
     * @param int $exp 过期时间戳
     * @param int $iat 签发时间戳
     * @param string $jti JWT ID
     * @param array|null $roles 用户角色列表
     * @param array|null $perms 用户权限列表
     * @param array|string|null $customData 自定义数据,可以是数组或加密字符串
     * @return static
     */
    public static function create(
        int $uid,
        string $username,
        string $platform,
        int $exp,
        int $iat,
        string $jti,
        ?array $roles = null,
        ?array $perms = null,
        array|string|null $customData = null
    ): static {
        $custom = [];
        
        // 处理自定义数据
        if (is_string($customData)) {
            // 如果是字符串,将其存储为加密数据
            $custom['encrypted_data'] = $customData;
        } elseif (is_array($customData)) {
            // 如果是数组,直接合并到custom字段
            $custom = $customData;
        }
        
        return new static(
            $uid,
            $username,
            $platform,
            $exp,
            $iat,
            $jti,
            $roles,
            $perms,
            $custom
        );
    }
}

// 1. 使用数组自定义数据
$payload = Payload::create(
    uid: 456,
    username: 'jane_doe',
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: uniqid('jwt_'),
    roles: ['user', 'editor'],
    perms: ['read', 'write'],
    customData: [
        'department' => 'Marketing',
        'level' => 3,
        'preferences' => [
            'theme' => 'dark',
            'language' => 'zh-CN'
        ]
    ]
);

// 2. 使用加密字符串自定义数据
$encryptedData = base64_encode(json_encode([
    'sensitive_info' => 'secret_data',
    'timestamp' => time()
]));

$payload = Payload::create(
    uid: 789,
    username: 'bob_smith',
    platform: 'mobile',
    exp: time() + 3600,
    iat: time(),
    jti: uniqid('jwt_'),
    roles: ['user'],
    perms: ['read'],
    customData: $encryptedData
);

// 从数组创建Payload(包含必需字段验证)
$data = [
    'uid' => 123,
    'username' => 'john_doe',
    'platform' => 'app',
    'exp' => time() + 3600,
    'iat' => time(),
    'jti' => uniqid('jwt_'),
    'roles' => ['user'],
    'perms' => ['read', 'write'],
    'custom' => [
        'department' => 'IT',
        'location' => 'Beijing'
    ]
];

$payload = Payload::fromArray($data);

// 获取所有自定义数据
$customData = $payload->getCustomData();

// 获取特定自定义数据
$department = $payload->getCustom('department', 'Unknown');

// 检查是否存在特定自定义数据
if ($payload->hasCustom('department')) {
    echo "Department: " . $payload->getCustom('department');
}

// 获取加密的自定义数据
$encryptedData = $payload->getEncryptedData();

// 检查是否存在加密的自定义数据
if ($payload->hasEncryptedData()) {
    $data = json_decode(base64_decode($encryptedData), true);
    // 处理解密后的数据
}

// 检查用户是否具有指定角色(使用严格比较)
if ($payload->hasRole('admin')) {
    // 用户具有管理员角色
}

// 检查用户是否具有指定权限(使用严格比较)
if ($payload->hasPermission('delete')) {
    // 用户具有删除权限
}

// 获取用户信息
$userInfo = $payload->getUserInfo();

// 检查Token是否已过期
if ($payload->isExpired()) {
    // Token已过期
}

// 获取剩余有效时间
$ttl = $payload->getTtl();

// 获取用户标识
$userIdentifier = $payload->getUserIdentifier();

namespace Kode\Jwt\Guard;

use Kode\Jwt\Contract\GuardInterface;
use Kode\Jwt\Storage\StorageInterface;

class SsoGuard implements GuardInterface
{
    public function __construct(
        private StorageInterface $storage
    ) {}

    public function isUnique(string $uid, string $platform): bool
    {
        $key = "sso:{$uid}:{$platform}";
        $existing = $this->storage->get($key);
        
        if ($existing) {
            // 可选:自动踢出旧 Token
            $this->storage->blacklist($existing);
            $this->storage->delete($key);
        }

        return true;
    }

    public function register(string $uid, string $platform, string $jti): void
    {
        $this->storage->set(
            "sso:{$uid}:{$platform}",
            $jti,
            config('jwts.guards.api.ttl')
        );
    }
}

namespace Kode\Jwt\Storage;

use Swoole\Coroutine\Redis as CoRedis;

class RedisStorage implements StorageInterface
{
    private ?CoRedis $redis = null;

    public function __construct()
    {
        $this->connect();
    }

    private function connect(): void
    {
        $config = config('jwts.storage.redis');
        $this->redis = new CoRedis();
        $this->redis->connect('127.0.0.1', 6379);
        $this->redis->auth($config['password'] ?? '');
        $this->redis->select($config['db'] ?? 0);
    }

    public function blacklist(string $jti, int $ttl = 3600): bool
    {
        return (bool)$this->redis->setex(
            "blacklist:{$jti}",
            $ttl,
            '1'
        );
    }

    public function isBlacklisted(string $jti): bool
    {
        return (bool)$this->redis->exists("blacklist:{$jti}");
    }
}

use Kode\Jwt\KodeJwt;

$payload = new Payload(
    uid: 123,
    username: 'john_doe',
    platform: 'app',
    exp: now()->addMinutes(1440)->getTimestamp(),
    iat: now()->getTimestamp(),
    jti: uniqid('jwt_'),
    roles: ['user'],
    perms: ['read', 'write']
);

$token = KodeJwt::guard('api')->issue($payload);

// 返回: ['token' => 'eyJ...', 'expires_in' => 1440, 'refresh_ttl' => 20160]

try {
    $payload = KodeJwt::guard('api')->authenticate($token);
    echo $payload->username; // john_doe
} catch (TokenInvalidException $e) {
    // 处理异常
}

$newToken = KodeJwt::guard('api')->refresh($oldToken);

KodeJwt::guard('api')->invalidate($token);

// 使用Builder的便捷方法
$token = KodeJwt::builder()
    ->setUid(123)
    ->setUsername('john_doe')
    ->setPlatform('app')
    ->setRoles(['user'])
    ->setPermissions(['read', 'write'])
    ->setCustom(['department' => 'IT'])
    ->issue();

// 获取用户的所有活跃Token
$tokens = KodeJwt::getUserTokens('123', 'app');

// 强制注销用户的所有Token
$count = KodeJwt::revokeUserTokens('123', 'app');

// 检查Token是否有效
$isValid = KodeJwt::isTokenValid($token);

// 获取Token详细信息
$info = KodeJwt::getTokenInfo($token);
// 返回: ['uid' => 123, 'platform' => 'app', 'exp' => 1234567890, ...]

// 清理过期的Token
$cleanedCount = KodeJwt::cleanExpired();

// 获取存储统计信息
$stats = KodeJwt::getStats();
// 返回: ['total' => 100, 'expired' => 20, 'active' => 80]

// 使用增强的Payload创建方法
// 1. 使用数组自定义数据
$payload = Payload::create(
    uid: 456,
    username: 'jane_doe',
    platform: 'web',
    exp: time() + 86400,
    iat: time(),
    jti: uniqid('jwt_'),
    roles: ['user'],
    perms: ['read', 'write'],
    customData: [
        'department' => 'Marketing',
        'level' => 3,
        'preferences' => [
            'theme' => 'dark',
            'language' => 'zh-CN'
        ]
    ]
);

// 2. 使用加密字符串自定义数据
$encryptedData = base64_encode(json_encode([
    'sensitive_info' => 'secret_data',
    'timestamp' => time()
]));

$payload = Payload::create(
    uid: 789,
    username: 'bob_smith',
    platform: 'mobile',
    exp: time() + 86400,
    iat: time(),
    jti: uniqid('jwt_'),
    customData: $encryptedData
);


Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

// 1. 初始化(使用内存存储,演示用)
KodeJwt::init([
    'guards' => [
        'api' => [
            'driver' => 'sso',
            'storage' => 'memory',
            'secret' => 'your-256-bit-secret-key',
        ],
    ],
]);

// 2. 签发 Token
$now = time();
$payload = Payload::create(
    uid: 1001,
    username: 'alice',
    platform: 'web',
    exp: $now + 3600,
    iat: $now,
    jti: Payload::generateJti(),    // 高熵 JTI
);
$token = KodeJwt::issue($payload)['token'];

// 3. 验证 Token
$verified = KodeJwt::authenticate($token);
echo $verified->username;  // alice

KodeJwt::init([
    'guards' => [
        'api' => [
            'driver'   => 'sso',
            'storage'  => 'redis',
            'algo'     => 'RS256',
            'secret'   => 'your-rs256-secret',
            'expected_claims' => [
                'iss' => 'https://auth.example.com',
                'aud' => ['api.example.com', 'mobile'],
            ],
            'clock_skew' => 30,
        ],
    ],
    'storage' => [
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => getenv('REDIS_PASSWORD'),
            'prefix' => 'kode:jwt:',
        ],
    ],
    'replay' => [
        'mode'          => 'strict',     // strict / lenient / off
        '

use Kode\Jwt\Security\AntiReplay;

$payload = Payload::create(
    uid: 1001,
    username: 'alice',
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: Payload::generateJti(),
    audience: ['api.example.com'],
    issuer:   'https://auth.example.com',
    subject:  'auth-service',
    nonce:    AntiReplay::generateNonce(16),  // 32 字节一次性 Nonce
    roles:    ['user', 'admin'],
    perms:    ['read', 'write'],
    customData: [
        'tenant_id'  => 't_42',
        'department' => 'IT',
    ],
);

$result = KodeJwt::issue($payload);
// ['token' => 'eyJ...', 'expires_in' => 3600, 'refresh_ttl' => 604800]

use Kode\Jwt\Exception\TokenInvalidException;
use Kode\Jwt\Exception\TokenBlacklistedException;
use Kode\Jwt\Exception\TokenReplayException;
use Kode\Jwt\Exception\TokenExpiredException;

try {
    $payload = KodeJwt::authenticate($token);
} catch (TokenReplayException $e) {
    // 重放攻击:记录安全日志、触发风控告警
    return response()->json(['error' => '请求被拒绝'], 401);
} catch (TokenBlacklistedException $e) {
    // 已注销:引导重新登录
    return response()->json(['error' => '会话已过期'], 401);
} catch (TokenExpiredException $e) {
    // 已过期:尝试 refresh
    return response()->json(['error' => '需要刷新'], 401);
} catch (TokenInvalidException $e) {
    // 签名错误 / 算法不匹配 / 业务声明不匹配
    return response()->json(['error' => '无效 Token'], 401);
}

use Kode\Jwt\KodeJwt;
use Kode\Jwt\Key\JwkFactory;

// 1. 生成 RSA 密钥对(私钥用于签发,公钥用于发布)
$keyPair = JwkFactory::generateRsaKeyPair(2048, 'kid-2026-01');

// 2. 创建 JWKS 发布器(公钥集合自动剥离私钥参数)
$jwksSet = $keyPair['public']->toJwkSet(); // 假设已包装为 JwkSet
$publisher = KodeJwt::jwksPublisher($jwksSet, maxAge: 3600);

// 3. 处理 HTTP 请求(传入 If-None-Match 头)
$response = $publisher->handle([
    'If-None-Match' => $_SERVER['HTTP_IF_NONE_MATCH'] ?? '',
]);

// 4. 输出响应(适配你框架的 Response 对象)
http_response_code($response->status);
foreach ($response->headers as $name => $value) {
    header("{$name}: {$value}");
}
echo $response->body;
// 命中协商缓存时返回 304 Not Modified,body 为空

use Kode\Jwt\KodeJwt;

// 1. 创建 Introspector(使用默认守卫)
$introspector = KodeJwt::introspector();

// 2. 内省 Token(自动完成验签 + 黑名单检查)
$response = $introspector->introspect(
    token: $bearerToken,
    expectedPlatform: 'web',
    clientId: 'client-app-001',
);

// 3. 输出 RFC 7662 标准响应
header('Content-Type: application/json');
echo $response->toJson();
// 有效 Token:{"active":true,"scope":"openid profile","client_id":"client-app-001","username":"alice","token_type":"Bearer","exp":1800000000,"iat":1700000000,"sub":"user-123","aud":"web","iss":"kode","jti":"..."}
// 无效 Token:{"active":false}

use Kode\Jwt\KodeJwt;

// 1. 创建 Discovery 配置
$config = KodeJwt::discoveryConfiguration(
    issuer: 'https://auth.example.com',
    authorizationEndpoint: 'https://auth.example.com/authorize',
    tokenEndpoint: 'https://auth.example.com/token',
    jwksUri: 'https://auth.example.com/.well-known/jwks',
    userinfoEndpoint: 'https://auth.example.com/userinfo',
    introspectionEndpoint: 'https://auth.example.com/introspect',
    revocationEndpoint: 'https://auth.example.com/revoke',
);

// 2. 创建发布器并处理请求
$publisher = KodeJwt::discoveryPublisher($config, maxAge: 86400);
$response = $publisher->handle([
    'If-None-Match' => $_SERVER['HTTP_IF_NONE_MATCH'] ?? '',
]);

http_response_code($response->status);
foreach ($response->headers as $name => $value) {
    header("{$name}: {$value}");
}
echo $response->body;

use Kode\Jwt\KodeJwt;

// 1. 从 Token 中的 scope 字符串构造
$scope = KodeJwt::scope('openid profile email');

// 2. 集合运算
$scope->has('openid');              // true
$scope->hasAny(['profile', 'phone']); // true
$scope->hasAll(['openid', 'phone']); // false
$scope->intersect(['openid', 'email'])->toArray(); // ['openid', 'email']
$scope->merge(['offline_access'])->toString();     // "openid profile email offline_access"

// 3. 校验
$scope->allAllowed(['openid', 'profile', 'email', 'address']); // true
$scope->allStandard();  // true(全部为 OIDC 标准 scope)

// 4. 嵌入 Token
$scope->__toString(); // "openid profile email"(可直接作为 Payload.scope)

use Kode\Jwt\KodeJwt;
use Kode\Jwt\Exception\TokenInvalidException;

$inspector = KodeJwt::claimInspector();

try {
    $inspector
        ->assertIssuer($payload, 'https://auth.example.com')
        ->assertAudience($payload, 'web')
        ->assertSubject($payload, 'user-123')
        ->assertTimeWindow($payload, clockSkew: 30)
        ->assertScopesAll($payload, ['openid', 'profile'])
        ->assertPlatform($payload, 'web')
        ->assertCustomEquals($payload, 'tenant', 'acme');
    // 全部通过
} catch (TokenInvalidException $e) {
    // 校验失败,$e->jti 携带 Token JTI 便于排查
    error_log("Token 校验失败:{$e->getMessage()} (jti={$e->jti})");
}

use Kode\Jwt\KodeJwt;

// 1. 链式构建策略
$policy = KodeJwt::tokenPolicy()
    ->withIssuer('https://auth.example.com')
    ->withAudience('web')
    ->withPlatform('web')
    ->withRequiredScopes(['openid', 'profile'])
    ->withAnyScopes(['read', 'write'])    // 至少满足一个
    ->withRequiredCustom(['tenant' => 'acme'])
    ->withClockSkew(30)
    ->withIgnoreExpiration(false);

// 2. enforce:失败抛异常
try {
    $policy->enforce($payload);
} catch (\Kode\Jwt\Exception\TokenInvalidException $e) {
    // ...
}

// 3. satisfies:不抛异常的判定版本
if ($policy->satisfies($payload)) {
    // 校验通过
}

// 4. 提取命中 scope
$allowedScope = $policy->extractAllowedScope($payload);

// 5. 序列化(用于配置缓存)
$array = $policy->toArray();
$policy2 = \Kode\Jwt\Policy\TokenPolicy::fromArray($array);

use Kode\Jwt\Key\JwkFactory;

// 生成 HS256 密钥(32 字节)
$jwk = JwkFactory::generateOctKey('HS256');
echo $jwk->toJson();
// {"kty":"oct","k":"...","use":"sig","alg":"HS256","kid":"oct-xxxx..."}

// 自动按算法选择密钥长度:HS256=32B / HS384=48B / HS512=64B

// 默认 2048 位(最低 2048,NIST 建议)
$pair = JwkFactory::generateRsaKeyPair(bits: 2048, alg: 'RS256');

$privateJwk = $pair['private'];   // 含 d/p/q/dp/dq/qi,用于签发
$publicJwk  = $pair['public'];    // 仅含 n/e,可安全分发

// 公钥分发前可再调用 toPublic() 防御性剥离
$distributable = $privateJwk->toPublic();

use Kode\Jwt\Key\KeyConverter;

// PEM → JWK
$jwk = KeyConverter::rsaPublicKeyToJwk('/path/to/public.pem', kid: 'key-1', alg: 'RS256');

// JWK → PEM(仅 RSA 公钥)
$pem = KeyConverter::jwkToPem($jwk);

use Kode\Jwt\Key\JwkSet;

$set = JwkSet::create()
    ->with($jwk1)
    ->with($jwk2);

// 按 kid 选择
$selected = $set->get('key-1');

// 按算法筛选
$candidates = $set->findByAlgorithm('RS256');

// 安全分发(自动剥离所有私钥参数)
$publicSet = $set->toPublic();

use Kode\Jwt\Security\Fingerprint;

$fp = new Fingerprint();

// 计算指纹(基于 UA + IP 前缀)
$context = [
    'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
    'ip'         => $_SERVER['REMOTE_ADDR'] ?? '',
];
$fingerprintHash = $fp->compute($context);

// 签发时绑定(业务层将 $fingerprintHash 写入 Payload.custom.fingerprint)
$payload = Payload::create(
    uid: 123,
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: Payload::generateJti(),
    customData: ['fingerprint' => $fingerprintHash],
);

// 验证时校验
$fp->ensureMatch($context, $payload->getCustom('fingerprint'));
// 不匹配时抛出 JwtException

// 单算法场景(默认)
'guards' => [
    'api' => [
        'algo' => 'RS256',
    ],
],

// 多算法并存场景(密钥轮换)
'guards' => [
    'api' => [
        'allowed_algorithms' => ['RS256', 'RS384'],  // 显式白名单
        // 'algo' 可不设置
    ],
],

// SQLite 方言
'INSERT OR REPLACE INTO ...'

// MySQL 方言
'INSERT ... ON DUPLICATE KEY UPDATE ...'

namespace Kode\Jwt\Contract;

interface SsoStorageInterface extends StorageInterface
{
    /** 原子化撤销(黑名单 + SSO 清理 + 用户列表清理 + 详情清理) */
    public function atomicRevoke(string $jti, string $uid, string $platform, int $ttl = 3600): int;

    /** 记录到用户活跃 Token 列表(最多保留 50 条) */
    public function trackUserToken(string $uid, string $platform, string $jti, int $ttl = 0): bool;

    /** 设置 SSO 平台 → JTI 映射 */
    public function setSsoMapping(string $uid, string $platform, string $jti, int $ttl = 0): bool;

    /** 获取 SSO 平台 → JTI 映射 */
    public function getSsoMapping(string $uid, string $platform): ?string;
}

use Kode\Jwt\Contract\SsoStorageInterface;

/** @var \Kode\Jwt\Contract\StorageInterface $storage */

// 通用调用:所有存储后端都支持
$storage->blacklist($jti, 3600);

// 高级能力:仅在支持时使用,否则降级
if ($storage instanceof SsoStorageInterface) {
    // 推荐:原子化撤销(生产环境使用 Redis 时为 Lua 脚本原子操作)
    $affected = $storage->atomicRevoke($jti, $uid, $platform, 3600);

    // 维护用户活跃 Token 列表
    $storage->trackUserToken($uid, $platform, $jti, 3600);

    // SSO 平台 → JTI 映射
    $storage->setSsoMapping($uid, $platform, $jti, 3600);
    $bound = $storage->getSsoMapping($uid, $platform);
} else {
    // 降级实现(顺序执行,非原子)
    $storage->blacklist($jti, 3600);
    $storage->delete("sso:{$uid}:{$platform}");
    $storage->delete("token:{$jti}");
}

return [
    'guards' => [
        'api' => [
            'driver'   => 'sso',
            'storage'  => 'redis',           // 指定 Redis 存储
            'algo'     => 'RS256',
            'ttl'      => 3600,
            'refresh_ttl' => 604800,
            'blacklist_enabled' => true,      // 启用黑名单
        ],
    ],
    'storage' => [
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => getenv('REDIS_PASSWORD'),
            'database' => 0,
            'prefix' => 'kode:jwt:',
            'persistent' => true,             // 长连接(可选)
            'persistent_id' => 'kode_jwt',
        ],
    ],
];

// 用户主动退出登录
KodeJwt::guard('api')->invalidate($token);

// 强制注销某用户某平台所有 Token
$count = KodeJwt::revokeUserTokens('123', 'app');

// 强制注销某用户所有平台 Token
$count = KodeJwt::revokeUserTokens('123');

return [
    'replay' => [
        'mode'         => 'strict',          // strict / lenient / off
        '',
        'ttl'          => 3600,              // Nonce 保留时间(秒)
    ],
];

$payload = Payload::create(
    uid: 123,
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: Payload::generateJti(),
    nonce: AntiReplay::generateNonce(16),    // 32 字节随机值
);
$token = KodeJwt::guard('api')->issue($payload);

return [
    'replay' => [
        'mode'         => 'lenient',
        'window'       => 60,                // 窗口大小(秒)
        'max_requests' => 5,                // 窗口内最大允许次数
    ],
];

use Kode\Jwt\Exception\TokenReplayException;
use Kode\Jwt\Exception\TokenBlacklistedException;

try {
    $payload = KodeJwt::guard('api')->authenticate($token);
} catch (TokenReplayException $e) {
    // 重放攻击:记录安全日志、触发风控告警
    security_log('replay_attack', [
        'jti'    => $e->getJti(),
        'nonce'  => $e->getNonce(),
        'time'   => $e->getReplayDetectedAt(),
    ]);
    return response()->json(['error' => '请求被拒绝'], 401);
} catch (TokenBlacklistedException $e) {
    // 已注销:引导重新登录
    return response()->json(['error' => '会话已过期'], 401);
}

return [
    'guards' => [
        'api' => [
            'algo' => 'RS256',
            'expected_claims' => [
                'iss' => 'https://auth.example.com',     // 签发者必须匹配
                'aud' => ['api.example.com', 'mobile'],  // 受众命中其一即可
                'sub' => 'auth-service',                 // 主体标识
                'tenant_id' => 'tenant_42',              // 自定义声明精确匹配
            ],
        ],
    ],
];

return [
    'guards' => [
        'api' => [
            'clock_skew' => 30,    // 允许 30 秒的时钟漂移
        ],
    ],
];

// 供 IDE 识别静态门面
/** @method static \Kode\Jwt\Token\Payload authenticate(string $token) */
/** @method static string issue(\Kode\Jwt\Token\Payload $payload) */
class KodeJwt {}

use Kode\Jwt\Token\Builder;

$builder = new Builder(['algo' => 'HS256']);
$builder->setUid(123);
$builder->setExpiration(time() + 3600);

// 多签配置
$signers = [
    ['key' => 'secret_key_1', 'keyId' => 'signer_a'],
    ['key' => 'secret_key_2', 'keyId' => 'signer_b'],
];

// 生成多签 JWS
$multiSigToken = $builder->buildMultiSignature($signers);

// 生成分离式签名
$detachedSig = $builder->buildDetachedSignature($signers);

use Kode\Jwt\OpenId\IdTokenBuilder;
use Kode\Jwt\OpenId\UserInfo;

// 构建 ID Token
$idTokenBuilder = new IdTokenBuilder([
    'secret' => 'your-secret',
    'issuer' => 'https://your-app.com',
]);

$idTokenBuilder
    ->setSubject('user-123')
    ->setAudience('client-app-id')
    ->setIssuer('https://your-app.com')
    ->setNonce('random-nonce-value')
    ->setAuthTime(time())
    ->setScopes(['openid', 'profile', 'email']);

$idToken = $idTokenBuilder->build();

// 用户信息
$userInfo = UserInfo::fromPayload($payload);
echo $userInfo->email;
echo $userInfo->name;

use Kode\Jwt\OAuth2\HybridProvider;

$provider = new HybridProvider([
    'secret' => 'your-secret',
    'access_token_ttl' => 3600,
    'refresh_token_ttl' => 86400,
    'issuer' => 'https://your-app.com',
]);

// Authorization Code 模式
$tokens = $provider->generateAuthorizationCodeTokens(
    clientId: 'client-app',
    userId: 123,
    scopes: ['openid', 'profile'],
    nonce: 'random-nonce'
);

// Implicit 模式
$tokens = $provider->generateImplicitTokens(
    clientId: 'client-app',
    userId: 123,
    scopes: ['openid'],
    state: 'state-value'
);

// Client Credentials 模式
$tokens = $provider->generateClientCredentialsTokens(
    clientId: 'client-app',
    scopes: ['api:read']
);

use Kode\Jwt\KeyRotation\KeyRotationManager;
use Kode\Jwt\Storage\MemoryStorage;

$storage = new MemoryStorage();
$rotationManager = new KeyRotationManager(
    storage: $storage,
    keyType: 'hmac',
    defaultKeyLifetime: 2592000,  // 30 天
    transitionPeriod: 604800      // 7 天过渡期
);

// 生成新主密钥
$newKey = $rotationManager->generateNewKey();

// 获取签名密钥(当前主密钥)
$signingKey = $rotationManager->getSigningKey();

// 获取验证密钥列表(主密钥 + 过渡期内旧密钥)
$verificationKeys = $rotationManager->getVerificationKeys();

// 自动轮换(主密钥即将过期时触发)
$rotationManager->autoRotate(86400); // 提前 1 天轮换

// 查看轮换状态
$status = $rotationManager->getRotationStatus();

use Kode\Jwt\Metrics\PrometheusMetrics;

$metrics = new PrometheusMetrics('kode_jwt');

// 记录 Token 操作
$metrics->recordTokenIssued('api', 'web');
$metrics->recordTokenAuthenticated('api');
$metrics->recordTokenRefreshed('api');
$metrics->recordTokenInvalidated('api');
$metrics->recordAuthenticationFailure('expired', 'api');

// 更新统计值
$metrics->setActiveTokens(150, 'api');
$metrics->setBlacklistedTokens(12, 'api');

// 计时操作
$result = $metrics->timeOperation('authenticate', function() use ($token) {
    return KodeJwt::authenticate($token);
});

// 导出 Prometheus 格式
echo $metrics->export();
// 输出:
// # HELP kode_jwt_tokens_issued_total Total count of tokens_issued_total
// # TYPE kode_jwt_tokens_issued_total counter
// kode_jwt_tokens_issued_total{guard="api",platform="web"} 1



declare(strict_types=1);

return [
    'defaults' => [
        'guard' => 'api',
        'provider' => 'users',
        'platform' => 'web',
    ],

    'guards' => [
        'api' => [
            'driver' => 'sso',
            'provider' => 'users',
            'storage' => 'redis',
            'blacklist_enabled' => true,
            'refresh_enabled' => true,
            'refresh_ttl' => 20160,
            'ttl' => 1440,
            'algo' => 'RS256',
            'public_key' => storage_path('keys/public.pem'),
            'private_key' => storage_path('keys/private.pem'),
        ],
    ],

    'storage' => [
        'redis' => [
            'connection' => 'default',
            'prefix' => 'kode:jwt:',
        ],
    ],
];



namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Kode\Jwt\KodeJwt;

class JwtServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton('kode.jwt', function ($app) {
            KodeJwt::detectAndLoadConfig();
            return KodeJwt::guard();
        });
    }

    public function boot(): void
    {
        // 发布配置文件
        $this->publishes([
            __DIR__ . '/../../config/jwt.php' => config_path('jwt.php'),
        ], 'jwt-config');
    }
}



namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Kode\Jwt\KodeJwt;
use Symfony\Component\HttpFoundation\Response;

class JwtAuthMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        $token = $request->bearerToken();

        if (!$token) {
            return response()->json(['error' => '未提供 Token'], 401);
        }

        try {
            $payload = KodeJwt::authenticate($token);
            $request->merge(['jwt_payload' => $payload]);
            return $next($request);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 401);
        }
    }
}

// app/Http/Kernel.php
protected $routeMiddleware = [
    'jwt.auth' => \App\Http\Middleware\JwtAuthMiddleware::class,
];



namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class AuthController extends Controller
{
    public function login()
    {
        $credentials = request()->validate([
            'email' => 'json(['error' => '凭据无效'], 401);
        }

        // 生成 Token
        $payload = Payload::create(
            uid: $user->id,
            username: $user->name,
            platform: 'web',
            exp: time() + 86400,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: [$user->role],
        );

        $result = KodeJwt::issue($payload);

        return response()->json([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ]);
    }

    public function me()
    {
        $payload = request()->get('jwt_payload');
        return response()->json([
            'id' => $payload->uid,
            'username' => $payload->username,
        ]);
    }

    public function refresh()
    {
        $token = request()->bearerToken();
        $result = KodeJwt::refresh($token);
        return response()->json([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ]);
    }

    public function logout()
    {
        $token = request()->bearerToken();
        KodeJwt::invalidate($token);
        return response()->json(['message' => '已注销']);
    }
}

// routes/api.php
Route::prefix('auth')->group(function () {
    Route::post('/login', [AuthController::class, 'login']);
    Route::middleware('jwt.auth')->group(function () {
        Route::get('/me', [AuthController::class, 'me']);
        Route::post('/refresh', [AuthController::class, 'refresh']);
        Route::post('/logout', [AuthController::class, 'logout']);
    });
});



declare(strict_types=1);

return [
    'defaults' => [
        'guard' => 'api',
        'provider' => 'users',
        'platform' => 'api',
    ],

    'guards' => [
        'api' => [
            'driver' => 'sso',
            'provider' => 'users',
            'storage' => 'coroutine_redis',
            'blacklist_enabled' => true,
            'refresh_enabled' => true,
            'refresh_ttl' => 20160,
            'ttl' => 1440,
            'algo' => 'RS256',
            'public_key' => BASE_PATH . '/storage/keys/public.pem',
            'private_key' => BASE_PATH . '/storage/keys/private.pem',
        ],
    ],

    'storage' => [
        'coroutine_redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => null,
            'database' => 0,
            'prefix' => 'kode:jwt:',
        ],
    ],
];



declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class AuthController
{
    public function login(RequestInterface $request, ResponseInterface $response)
    {
        $credentials = $request->all();

        // 验证用户(示例)
        $user = $this->validateUser($credentials);

        // 生成 Token
        $payload = Payload::create(
            uid: $user['id'],
            username: $user['name'],
            platform: 'api',
            exp: time() + 86400,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: [$user['role'] ?? 'user'],
        );

        $result = KodeJwt::issue($payload);

        return $response->json([
            'code' => 0,
            'data' => [
                'token' => $result['token'],
                'expires_in' => $result['expires_in'],
            ],
        ]);
    }

    public function user(RequestInterface $request)
    {
        $payload = $request->getAttribute('jwt_payload');

        return [
            'code' => 0,
            'data' => [
                'id' => $payload->uid,
                'username' => $payload->username,
            ],
        ];
    }

    private function validateUser(array $credentials): array
    {
        // 实现用户验证逻辑
        return [
            'id' => 1,
            'name' => 'test_user',
            'role' => 'admin',
        ];
    }
}



declare(strict_types=1);

namespace App\Middleware;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Kode\Jwt\KodeJwt;

class JwtAuthMiddleware
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): PsrResponseInterface
    {
        $token = $request->getHeader('Authorization')[0] ?? '';

        if (!$token) {
            return (new ResponseInterface())->json([
                'code' => 401,
                'message' => '未提供 Token',
            ]);
        }

        $token = str_replace('Bearer ', '', $token);

        try {
            $payload = KodeJwt::authenticate($token);
            
            // 将 payload 添加到请求属性中
            $request = $request->withAttribute('jwt_payload', $payload);
            
            return $handler->handle($request);
        } catch (\Exception $e) {
            return (new ResponseInterface())->json([
                'code' => 401,
                'message' => $e->getMessage(),
            ]);
        }
    }
}

// config/autoload/middlewares.php
return [
    'http' => [
        \App\Middleware\JwtAuthMiddleware::class,
    ],
];



declare(strict_types=1);

return [
    'defaults' => [
        'guard' => 'api',
        'provider' => 'users',
        'platform' => 'web',
    ],

    'guards' => [
        'api' => [
            'driver' => 'sso',
            'provider' => 'users',
            'storage' => 'redis',
            'blacklist_enabled' => true,
            'refresh_enabled' => true,
            'refresh_ttl' => 20160,
            'ttl' => 1440,
            'algo' => 'RS256',
            'public_key' => runtime_path() . 'keys/public.pem',
            'private_key' => runtime_path() . 'keys/private.pem',
        ],
    ],

    'storage' => [
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => '',
            'database' => 0,
            'prefix' => 'kode:jwt:',
        ],
    ],
];



declare(strict_types=1);

namespace app\base;

use think\App;
use think\Controller;
use Kode\Jwt\KodeJwt;

abstract class AuthController extends Controller
{
    protected ?object $jwtPayload = null;

    protected function initialize(): void
    {
        parent::initialize();
        
        $token = $this->request->header('Authorization');
        $token = $token ? str_replace('Bearer ', '', $token) : '';

        if (!$token) {
            $this->error('未提供 Token', [], 401);
        }

        try {
            $this->jwtPayload = KodeJwt::authenticate($token);
        } catch (\Exception $e) {
            $this->error($e->getMessage(), [], 401);
        }
    }

    protected function getUserId(): int|string
    {
        return $this->jwtPayload->uid;
    }

    protected function getUserPayload(): object
    {
        return $this->jwtPayload;
    }
}



declare(strict_types=1);

namespace app\controller;

use app\base\AuthController;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class Auth extends AuthController
{
    public function login()
    {
        $credentials = $this->request->post();

        // 验证用户
        $user = \app\model\User::where('email', $credentials['email'] ?? '')->find();

        if (!$user || !password_verify($credentials['password'] ?? '', $user->password)) {
            $this->error('凭据无效');
        }

        $payload = Payload::create(
            uid: $user->id,
            username: $user->name,
            platform: 'web',
            exp: time() + 86400,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: [$user->role],
        );

        $result = KodeJwt::issue($payload);

        return json([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ]);
    }

    public function me()
    {
        return json([
            'id' => $this->getUserId(),
            'username' => $this->jwtPayload->username,
        ]);
    }

    public function refresh()
    {
        $token = $this->request->header('Authorization');
        $token = $token ? str_replace('Bearer ', '', $token) : '';

        $result = KodeJwt::refresh($token);

        return json([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ]);
    }

    public function logout()
    {
        $token = $this->request->header('Authorization');
        $token = $token ? str_replace('Bearer ', '', $token) : '';

        KodeJwt::invalidate($token);

        return json(['message' => '已注销']);
    }
}

// route/app.php
use app\controller\Auth;

Route::post('auth/login', [Auth::class, 'login']);
Route::group(function () {
    Route::get('auth/me', [Auth::class, 'me']);
    Route::post('auth/refresh', [Auth::class, 'refresh']);
    Route::post('auth/logout', [Auth::class, 'logout']);
})->middleware(\app\middleware\AuthMiddleware::class);



declare(strict_types=1);

Jwt\Token\Payload;

// 初始化(使用默认配置或加载配置文件)
KodeJwt::detectAndLoadConfig();

// 或手动配置
KodeJwt::init([
    'defaults' => [
        'guard' => 'api',
        'storage' => 'memory',
    ],
    'guards' => [
        'api' => [
            'driver' => 'sso',
            'storage' => 'memory',
            'algo' => 'HS256',
            'secret' => file_get_contents(__DIR__ . '/storage/keys/secret'),
            'ttl' => 3600,
            'refresh_ttl' => 604800,
        ],
    ],
]);

// 生成 Token
$payload = Payload::create(
    uid: 'user_123',
    username: 'test_user',
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: uniqid('jwt_'),
);

$result = KodeJwt::issue($payload);
$token = $result['token'];

echo "Token: {$token}\n";

// 验证 Token
try {
    $payload = KodeJwt::authenticate($token);
    echo "用户: {$payload->username}\n";
    echo "过期时间: " . date('Y-m-d H:i:s', $payload->exp) . "\n";
} catch (\Exception $e) {
    echo "验证失败: {$e->getMessage()}\n";
}

// 刷新 Token
$newResult = KodeJwt::refresh($token);
echo "新 Token: {$newResult['token']}\n";

// 注销 Token
KodeJwt::invalidate($token);
echo "已注销\n";



namespace App\Security;

use Kode\Jwt\KodeJwt;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;

class JwtAuthenticator extends AbstractAuthenticator
{
    public function __construct(
        private KodeJwt $jwtService
    ) {}

    public function supports(Request $request): ?bool
    {
        return $request->headers->has('Authorization');
    }

    public function authenticate(Request $request): SelfValidatingPassport
    {
        $token = $request->headers->get('Authorization');
        $token = str_replace('Bearer ', '', $token);

        $payload = $this->jwtService->authenticate($token);

        return new SelfValidatingPassport(
            new UserBadge($payload->uid, function () use ($payload) {
                return new User($payload->uid, [], [], $payload->roles ?? []);
            })
        );
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return new JsonResponse(['error' => '认证失败'], 401);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return null;
    }
}



return [
    'components' => [
        'jwt' => [
            'class' => 'Kode\Jwt\KodeJwt',
            'config' => [
                'defaults' => [
                    'guard' => 'api',
                    'provider' => 'user',
                    'platform' => 'web',
                ],
                'guards' => [
                    'api' => [
                        'driver' => 'sso',
                        'provider' => 'user',
                        'storage' => 'redis',
                        'blacklist_enabled' => true,
                        'refresh_enabled' => true,
                        'refresh_ttl' => 20160,
                        'ttl' => 1440,
                        'algo' => 'RS256',
                        'public_key' => '@app/runtime/keys/public.pem',
                        'private_key' => '@app/runtime/keys/private.pem',
                    ],
                ],
                'storage' => [
                    'redis' => [
                        'connection' => 'default',
                        'prefix' => 'kode:jwt:',
                    ],
                ],
            ],
        ],
    ],
];



namespace app\commands;

use Yii;
use yii\console\Controller;
use Kode\Jwt\KodeJwt;

class JwtController extends Controller
{
    public function actionInit()
    {
        $keyDir = Yii::getAlias('@app/runtime/keys');
        
        if (!is_dir($keyDir)) {
            mkdir($keyDir, 0755, true);
        }
        
        KodeJwt::init([
            'defaults' => [
                'guard' => 'api',
            ],
            'guards' => [
                'api' => [
                    'driver' => 'sso',
                    'storage' => 'redis',
                    'algo' => 'RS256',
                    'public_key' => $keyDir . '/public.pem',
                    'private_key' => $keyDir . '/private.pem',
                    'ttl' => 1440,
                    'refresh_ttl' => 20160,
                ],
            ],
        ]);
        
        $result = KodeJwt::generateKeys('rsa', $keyDir);
        
        if ($result['success']) {
            echo "✅ 密钥生成成功!\n";
            echo "私钥: {$result['private_key_path']}\n";
            echo "公钥: {$result['public_key_path']}\n";
        } else {
            echo "❌ 密钥生成失败: {$result['error']}\n";
        }
    }
}



namespace app\components;

use Yii;
use yii\base\Behavior;
use yii\web\Controller;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class AuthenticatedBehavior extends Behavior
{
    public function events()
    {
        return [
            Controller::EVENT_BEFORE_ACTION => 'beforeAction',
        ];
    }

    public function beforeAction($action)
    {
        $request = Yii::$app->request;
        $authHeader = $request->getHeaders()->get('Authorization');
        
        if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) {
            Yii::$app->response->statusCode = 401;
            echo json_encode(['error' => '未提供认证令牌']);
            return false;
        }
        
        $token = substr($authHeader, 7);
        
        try {
            $payload = KodeJwt::authenticate($token);
            
            Yii::$app->user->identity = $this->findUser($payload->uid);
            Yii::$app->jwtPayload = $payload;
            
            return true;
        } catch (\Exception $e) {
            Yii::$app->response->statusCode = 401;
            echo json_encode(['error' => '认证失败: ' . $e->getMessage()]);
            return false;
        }
    }
    
    protected function findUser($uid)
    {
        return \app\models\User::findOne($uid);
    }
}



namespace app\controllers;

use Yii;
use yii\rest\Controller;
use app\components\AuthenticatedBehavior;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class ApiController extends Controller
{
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['auth'] = AuthenticatedBehavior::class;
        return $behaviors;
    }
    
    public function actionLogin()
    {
        $request = Yii::$app->request;
        $username = $request->post('username');
        $password = $request->post('password');
        
        $user = \app\models\User::findOne(['username' => $username]);
        
        if (!$user || !$user->validatePassword($password)) {
            throw new \yii\web\UnauthorizedHttpException('用户名或密码错误');
        }
        
        $payload = Payload::create(
            uid: $user->id,
            username: $user->username,
            platform: 'web',
            exp: time() + 1440 * 60,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: [$user->role],
        );
        
        $result = KodeJwt::issue($payload);
        
        return [
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
            'refresh_ttl' => $result['refresh_ttl'],
        ];
    }
    
    public function actionProfile()
    {
        $payload = Yii::$app->jwtPayload;
        
        return [
            'uid' => $payload->uid,
            'username' => $payload->username,
            'roles' => $payload->roles,
        ];
    }
    
    public function actionRefresh()
    {
        $request = Yii::$app->request;
        $refreshToken = $request->post('refresh_token');
        
        $result = KodeJwt::refresh($refreshToken);
        
        return [
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ];
    }
    
    public function actionLogout()
    {
        $request = Yii::$app->request;
        $token = $request->post('token');
        
        KodeJwt::invalidate($token);
        
        return ['message' => '已成功注销'];
    }
}



return [
    'Jwt' => [
        'defaults' => [
            'guard' => 'api',
            'provider' => 'Users',
            'platform' => 'web',
        ],
        'guards' => [
            'api' => [
                'driver' => 'sso',
                'provider' => 'Users',
                'storage' => 'redis',
                'blacklist_enabled' => true,
                'refresh_enabled' => true,
                'refresh_ttl' => 20160,
                'ttl' => 1440,
                'algo' => 'RS256',
                'public_key' => ROOT . '/config/keys/public.pem',
                'private_key' => ROOT . '/config/keys/private.pem',
            ],
        ],
        'storage' => [
            'redis' => [
                'connection' => 'default',
                'prefix' => 'kode:jwt:',
            ],
        ],
    ],
];

use Kode\Jwt\KodeJwt;

$jwtConfig = 



namespace App\Shell;

use Cake\Console\Shell;
use Kode\Jwt\KodeJwt;

class JwtShell extends Shell
{
    public function main()
    {
        $keyDir = ROOT . '/config/keys';
        
        if (!is_dir($keyDir)) {
            mkdir($keyDir, 0755, true);
        }
        
        $this->out('正在生成 RSA 密钥对...');
        
        $result = KodeJwt::generateKeys('rsa', $keyDir);
        
        if ($result['success']) {
            $this->out('<success>✅ 密钥生成成功!</success>');
            $this->out("私钥: {$result['private_key_path']}");
            $this->out("公钥: {$result['public_key_path']}");
        } else {
            $this->out('<error>❌ 密钥生成失败: ' . $result['error'] . '</error>');
        }
    }
}



namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class JwtAuthenticationMiddleware
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $authHeader = $request->getHeaderLine('Authorization');
        
        if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) {
            return $this->unauthorizedResponse('未提供认证令牌');
        }
        
        $token = substr($authHeader, 7);
        
        try {
            $payload = KodeJwt::authenticate($token);
            
            $request = $request->withAttribute('jwt_payload', $payload);
            $request = $request->withAttribute('user_id', $payload->uid);
            
            return $handler->handle($request);
        } catch (\Exception $e) {
            return $this->unauthorizedResponse('认证失败: ' . $e->getMessage());
        }
    }
    
    protected function unauthorizedResponse(string $message): ResponseInterface
    {
        return new \ Laminas\Diactoros\Response\JsonResponse([
            'error' => $message,
        ], 401);
    }
}

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue->add(new \App\Middleware\JwtAuthenticationMiddleware());
    
    return $middlewareQueue;
}



namespace App\Controller;

use Cake\Controller\Controller;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class AuthController extends Controller
{
    public function login()
    {
        $username = $this->request->getData('username');
        $password = $this->request->getData('password');
        
        $user = $this->Users->findByUsername($username)->first();
        
        if (!$user || !$user->verifyPassword($password)) {
            $this->response = $this->response->withStatus(401);
            $this->set(['error' => '用户名或密码错误']);
            $this->set('_serialize', ['error']);
            return;
        }
        
        $payload = Payload::create(
            uid: $user->id,
            username: $user->username,
            platform: 'web',
            exp: time() + 1440 * 60,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: [$user->role],
        );
        
        $result = KodeJwt::issue($payload);
        
        $this->set([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
            'refresh_ttl' => $result['refresh_ttl'],
        ]);
        $this->set('_serialize', ['token', 'expires_in', 'refresh_ttl']);
    }
    
    public function profile()
    {
        $payload = $this->request->getAttribute('jwt_payload');
        
        $this->set([
            'uid' => $payload->uid,
            'username' => $payload->username,
            'roles' => $payload->roles,
        ]);
        $this->set('_serialize', ['uid', 'username', 'roles']);
    }
    
    public function refresh()
    {
        $refreshToken = $this->request->getData('refresh_token');
        
        $result = KodeJwt::refresh($refreshToken);
        
        $this->set([
            'token' => $result['token'],
            'expires_in' => $result['expires_in'],
        ]);
        $this->set('_serialize', ['token', 'expires_in']);
    }
    
    public function logout()
    {
        $token = $this->request->getData('token');
        
        KodeJwt::invalidate($token);
        
        $this->set(['message' => '已成功注销']);
        $this->set('_serialize', ['message']);
    }
}



namespace App\Controller\Component;

use Cake\Controller\Component;
use Kode\Jwt\KodeJwt;
use Kode\Jwt\Token\Payload;

class JwtComponent extends Component
{
    protected $_defaultConfig = [
        'guard' => 'api',
    ];
    
    public function initialize(array $config): void
    {
        parent::initialize($config);
        
        KodeJwt::detectAndLoadConfig();
    }
    
    public function issue(array $userData, string $platform = 'web'): array
    {
        $payload = Payload::create(
            uid: $userData['id'],
            username: $userData['username'] ?? null,
            platform: $platform,
            exp: time() + 1440 * 60,
            iat: time(),
            jti: uniqid('jwt_'),
            roles: $userData['roles'] ?? null,
            perms: $userData['perms'] ?? null,
        );
        
        return KodeJwt::issue($payload);
    }
    
    public function authenticate(string $token): Payload
    {
        return KodeJwt::authenticate($token);
    }
    
    public function refresh(string $token): array
    {
        return KodeJwt::refresh($token);
    }
    
    public function invalidate(string $token): void
    {
        KodeJwt::invalidate($token);
    }
    
    public function getPayload(): ?Payload
    {
        return $this->getController()->request->getAttribute('jwt_payload');
    }
    
    public function getUserId(): mixed
    {
        $payload = $this->getPayload();
        return $payload?->uid;
    }
    
    public function hasRole(string $role): bool
    {
        $payload = $this->getPayload();
        return $payload && in_array($role, $payload->roles ?? []);
    }
    
    public function hasPermission(string $permission): bool
    {
        $payload = $this->getPayload();
        return $payload && in_array($permission, $payload->perms ?? []);
    }
}



namespace App\Controller;

class ApiController extends Controller
{
    public function initialize(): void
    {
        parent::initialize();
        $this->loadComponent('Jwt');
    }
    
    public function protectedAction()
    {
        $userId = $this->Jwt->getUserId();
        $hasAdminRole = $this->Jwt->hasRole('admin');
        
        $this->set(compact('userId', 'hasAdminRole'));
    }
}

// 方式1:自动检测并加载配置文件
KodeJwt::detectAndLoadConfig();

// 方式2:手动初始化(使用默认配置)
KodeJwt::init();

// 方式3:手动初始化(使用自定义配置)
KodeJwt::init([
    'defaults' => [
        'guard' => 'api',
        'platform' => 'web',
    ],
    'guards' => [
        'api' => [
            'driver' => 'sso',
            'storage' => 'redis',
            'algo' => 'RS256',
            'ttl' => 1440,
        ],
    ],
]);

// 方式4:从文件加载配置
KodeJwt::loadConfigFromFile('/path/to/config/jwt.php');

// 获取默认守卫
$guard = KodeJwt::guard();

// 获取指定守卫
$guard = KodeJwt::guard('api');

// 获取默认守卫(别名)
$guard = KodeJwt::guard('default');

// 签发 Token
$result = KodeJwt::issue(Payload $payload): array;
// 返回: ['token' => string, 'expires_in' => int, 'refresh_ttl' => int]

// 验证 Token 并返回 Payload
$payload = KodeJwt::authenticate(string $token): Payload;

// 刷新 Token
$result = KodeJwt::refresh(string $token): array;
// 返回: ['token' => string, 'expires_in' => int]

// 注销 Token(加入黑名单)
KodeJwt::invalidate(string $token): void;

// 检查 Token 是否有效
$isValid = KodeJwt::isTokenValid(string $token): bool;

// 获取 Token 详细信息
$info = KodeJwt::getTokenInfo(string $token): array;
// 返回: ['uid' => int|string, 'platform' => string, 'exp' => int, ...]

// 获取用户的所有活跃 Token
$tokens = KodeJwt::getUserTokens(int|string $uid, string $platform): array;

// 强制注销用户的所有 Token
$count = KodeJwt::revokeUserTokens(int|string $uid, string $platform): int;

// 清理过期的 Token
$count = KodeJwt::cleanExpired(): int;

// 获取存储统计信息
$stats = KodeJwt::getStats(): array;
// 返回: ['total' => int, 'expired' => int, 'active' => int]

// 获取防重放保护器
$replay = KodeJwt::antiReplay(): ?AntiReplay;

// 生成一次性 Nonce(32 字节随机值)
$nonce = AntiReplay::generateNonce(16);

// 手动消费 Nonce(高级用法,通常由 Guard 自动调用)
$passed = $replay->check($jti, $nonce, $ttl);

// 查询 Nonce 是否已被消费
$seen = $replay->seen($jti, $nonce);

// 检查是否启用
$enabled = $replay->isEnabled();

// 生成密钥对
$result = KodeJwt::generateKeys(string $type, ?string $path = null): array;
// $type: 'rsa' | 'hmac'
// 返回: ['success' => bool, 'private_key_path' => string, 'public_key_path' => string, 'error' => string]

// 示例
$result = KodeJwt::generateKeys('rsa', '/path/to/keys');
if ($result['success']) {
    echo "私钥: {$result['private_key_path']}";
    echo "公钥: {$result['public_key_path']}";
}

// 获取事件调度器实例
$events = KodeJwt::events(): EventDispatcher;

// 监听事件
KodeJwt::events()->on(TokenIssued::class, function ($event) {
    // $event->payload
});

// 移除监听器
KodeJwt::events()->off(TokenIssued::class);

// 方式1:使用构造函数
$payload = new Payload(
    uid: 123,
    username: 'john_doe',
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: uniqid('jwt_'),
    roles: ['user'],
    perms: ['read', 'write'],
    custom: ['department' => 'IT']
);

// 方式2:使用静态方法 create()
$payload = Payload::create(
    uid: 123,
    username: 'john_doe',
    platform: 'web',
    exp: time() + 3600,
    iat: time(),
    jti: uniqid('jwt_'),
    roles: ['user'],
    perms: ['read', 'write'],
    customData: ['department' => 'IT']
);

// 方式3:从数组创建
$payload = Payload::fromArray([
    'uid' => 123,
    'username' => 'john_doe',
    'platform' => 'web',
    'exp' => time() + 3600,
    'iat' => time(),
    'jti' => uniqid('jwt_'),
    'roles' => ['user'],
    'perms' => ['read', 'write'],
    'custom' => ['department' => 'IT'],
]);

// 转换为数组
$array = $payload->toArray(): array;

// 获取自定义数据
$custom = $payload->getCustomData(): array;

// 获取特定自定义数据
$value = $payload->getCustom(string $key, mixed $default = null): mixed;

// 检查自定义数据是否存在
$exists = $payload->hasCustom(string $key): bool;

// 检查是否具有角色
$hasRole = $payload->hasRole(string $role): bool;

// 检查是否具有权限
$hasPerm = $payload->hasPermission(string $permission): bool;

// 获取用户信息
$userInfo = $payload->getUserInfo(): array;

// 检查是否已过期
$isExpired = $payload->isExpired(): bool;

// 获取剩余有效时间(秒)
$ttl = $payload->getTtl(): int;

// 获取用户标识
$userId = $payload->getUserIdentifier(): mixed;

// 🆕 获取一次性 Nonce
$nonce = $payload->getNonce(): ?string;

// 🆕 获取受众(aud)
$aud = $payload->getAudience(): string|array|null;

// 🆕 获取签发者(iss)
$iss = $payload->getIssuer(): ?string;

// 🆕 获取主体(sub)
$sub = $payload->getSubject(): ?string;

// 🆕 生成高熵 JTI(32 字节随机值)
$jti = Payload::generateJti(): string;

use Kode\Jwt\Contract\GuardInterface;

interface GuardInterface
{
    // 签发 Token
    public function issue(Payload $payload): array;

    // 验证 Token
    public function authenticate(string $token): Payload;

    // 刷新 Token
    public function refresh(string $token): array;

    // 注销 Token
    public function invalidate(string $token): void;

    // 检查 Token 是否有效
    public function isValid(string $token): bool;

    // 获取 Token 信息
    public function getTokenInfo(string $token): array;
}

use Kode\Jwt\Contract\StorageInterface;

interface StorageInterface
{
    // 设置缓存
    public function set(string $key, mixed $value, int $ttl = 0): bool;

    // 获取缓存
    public function get(string $key, mixed $default = null): mixed;

    // 删除缓存
    public function delete(string $key): bool;

    // 检查键是否存在
    public function has(string $key): bool;

    // 加入黑名单
    public function blacklist(string $jti, int $ttl = 3600): bool;

    // 检查是否在黑名单中
    public function isBlacklisted(string $jti): bool;

    // 批量设置
    public function setMultiple(array $values, int $ttl = 0): bool;

    // 批量获取
    public function getMultiple(array $keys, mixed $default = null): array;

    // 批量删除
    public function deleteMultiple(array $keys): bool;

    // 清空所有缓存
    public function flush(): bool;

    // 获取存储统计信息
    public function stats(): array;
}

use Kode\Jwt\Event\TokenIssued;

$event = new TokenIssued(Payload $payload);

// 访问 Payload
$uid = $event->payload->uid;
$jti = $event->payload->jti;

use Kode\Jwt\Event\TokenExpired;

$event = new TokenExpired(Payload $payload);

use Kode\Jwt\Event\TokenRevoked;

$event = new TokenRevoked(Payload $payload);

use Kode\Jwt\Exception\TokenInvalidException;
use Kode\Jwt\Exception\TokenExpiredException;
use Kode\Jwt\Exception\TokenBlacklistedException;

// Token 无效
throw new TokenInvalidException(string $message = '');

// Token 已过期
throw new TokenExpiredException(string $message = '');

// Token 在黑名单中
throw new TokenBlacklistedException(string $message = '');

// 推荐:使用环境变量
$secret = getenv('JWT_SECRET') ?: $_ENV['JWT_SECRET'];

// 或从文件加载
$privateKey = file_get_contents(storage_path('keys/private.pem'));
$publicKey = file_get_contents(storage_path('keys/public.pem'));

// 配置
KodeJwt::init([
    'guards' => [
        'api' => [
            'algo' => 'RS256',
            'private_key' => $privateKey,
            'public_key' => $publicKey,
        ],
    ],
]);

return [
    'defaults' => [
        'guard' => 'api',
    ],

    'guards' => [
        'api' => [
            'driver' => 'sso',
            'storage' => 'redis',
            'algo' => 'RS256',
            'ttl' => 3600,
            'platform' => null,
        ],
        'admin' => [
            'driver' => 'sso',
            'storage' => 'redis',
            'algo' => 'RS256',
            'ttl' => 1800, // 管理员 Token 更短
            'platform' => 'admin',
        ],
        'mobile' => [
            'driver' => 'mlo', // 多点登录
            'storage' => 'redis',
            'algo' => 'HS256',
            'ttl' => 86400,
            'max_devices' => 3,
        ],
    ],
];

use Kode\Jwt\KodeJwt;

// Token 签发事件
KodeJwt::events()->on(\Kode\Jwt\Event\TokenIssued::class, function ($event) {
    error_log("Token 签发: uid={$event->payload->uid}, jti={$event->payload->jti}");
});

// Token 注销事件
KodeJwt::events()->on(\Kode\Jwt\Event\TokenRevoked::class, function ($event) {
    error_log("Token 注销: uid={$event->payload->uid}");
});

use Kode\Jwt\Exception\TokenInvalidException;
use Kode\Jwt\Exception\TokenExpiredException;
use Kode\Jwt\Exception\TokenBlacklistedException;

try {
    $payload = KodeJwt::authenticate($token);
} catch (TokenInvalidException $e) {
    // Token 无效(签名错误)
    return response()->json(['error' => 'Token 无效'], 401);
} catch (TokenExpiredException $e) {
    // Token 已过期
    return response()->json(['error' => 'Token 已过期,请刷新'], 401);
} catch (TokenBlacklistedException $e) {
    // Token 已被加入黑名单
    return response()->json(['error' => 'Token 已被注销'], 401);
} catch (\Exception $e) {
    // 其他错误
    return response()->json(['error' => '认证失败'], 500);
}

namespace App\Storage;

use Kode\Jwt\Contract\StorageInterface;

class CustomStorage implements StorageInterface
{
    public function set(string $key, mixed $value, int $ttl = 0): bool
    {
        // 实现逻辑
    }

    public function get(string $key, mixed $default = null): mixed
    {
        // 实现逻辑
    }

    public function delete(string $key): bool
    {
        // 实现逻辑
    }

    public function has(string $key): bool
    {
        // 实现逻辑
    }

    public function cleanExpired(): int
    {
        // 实现逻辑
    }

    public function getStats(): array
    {
        // 实现逻辑
    }
}

KodeJwt::init([
    'guards' => [
        'api' => [
            'driver' => 'sso',
            'storage' => 'custom', // 使用自定义存储
        ],
    ],
    'storage' => [
        'custom' => [
            'driver' => \App\Storage\CustomStorage::class,
        ],
    ],
]);

namespace App\Guard;

use Kode\Jwt\Contract\GuardInterface;
use Kode\Jwt\Contract\StorageInterface;
use Kode\Jwt\Token\Payload;

class CustomGuard implements GuardInterface
{
    public function __construct(
        private StorageInterface $storage,
        private array $config
    ) {}

    public function issue(Payload $payload): array
    {
        // 自定义签发逻辑
    }

    public function authenticate(string $token): Payload
    {
        // 自定义验证逻辑
    }

    public function refresh(string $token): array
    {
        // 自定义刷新逻辑
    }

    public function invalidate(string $token): bool
    {
        // 自定义注销逻辑
    }

    public function validateToken(string $token): bool
    {
        // 自定义验证逻辑
    }
}
bash
# 进入你的项目目录
cd /path/to/your/project

# 安装配置文件和生成密钥(RSA 密钥对 + HMAC 密钥)
php vendor/bin/jwt install

# 或者仅生成配置文件
php vendor/bin/jwt install --config-only

# 或者仅生成密钥
php vendor/bin/jwt install --key-only

# 强制覆盖已存在的文件
php vendor/bin/jwt install --force
bash
# 生成 RSA 密钥对(默认)
php jwt key rsa

# 生成 HMAC 密钥
php jwt key hmac

# 生成并输出到控制台
php jwt key rsa stdout

# 强制覆盖现有密钥
php jwt key rsa --force
bash
# 生成 Token
php bin/jwt token generate --uid=123 --username=john --platform=web

# 验证 Token
php bin/jwt token verify --token=eyJ...

# 刷新 Token
php bin/jwt token refresh --token=eyJ...

# 注销 Token
php bin/jwt token invalidate --token=eyJ...

# 查看 Token 信息
php bin/jwt token info --token=eyJ...
bash
# 安装依赖
composer 生成 config/jwt.php)
php artisan jwt:install

# 生成密钥
php artisan jwt:key
bash
php yii jwt/init
bash
# 下载并解压包后
php bin/jwt install --config-only
php bin/jwt key rsa --force