来宾市万年长

PHP中四种主流Token实现方案

2026-03-24 14:14:02 浏览次数:2
详细信息

1. JWT (JSON Web Token)

最流行的无状态Token方案

实现方式:

// 使用firebase/php-jwt库
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class JWTToken {
    private $secretKey = 'your-secret-key';

    public function createToken($userId, $data = []) {
        $payload = [
            'user_id' => $userId,
            'data' => $data,
            'iat' => time(),
            'exp' => time() + 3600 // 1小时过期
        ];

        return JWT::encode($payload, $this->secretKey, 'HS256');
    }

    public function validateToken($token) {
        try {
            $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256'));
            return (array)$decoded;
        } catch (\Exception $e) {
            return false;
        }
    }
}

优点:

缺点:

2. OAuth2 Access Token

标准的授权框架方案

实现方式:

// 使用league/oauth2-server库
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Grant\PasswordGrant;

class OAuthToken {
    private $server;

    public function __construct() {
        // 初始化客户端存储、scope存储、token存储等
        $clientRepository = new ClientRepository();
        $scopeRepository = new ScopeRepository();
        $accessTokenRepository = new AccessTokenRepository();

        $this->server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            'path/to/private.key',
            'path/to/public.key'
        );

        // 配置授权类型
        $grant = new PasswordGrant(
            new UserRepository(),
            new RefreshTokenRepository()
        );
        $grant->setRefreshTokenTTL(new \DateInterval('P1M'));
        $this->server->enableGrantType($grant, new \DateInterval('PT1H'));
    }

    public function issueToken($username, $password) {
        $request = new ServerRequest('POST', '/token');
        $request = $request->withParsedBody([
            'grant_type' => 'password',
            'username' => $username,
            'password' => $password
        ]);

        return $this->server->respondToAccessTokenRequest($request, new Response());
    }
}

优点:

缺点:

3. 数据库Session Token

传统的有状态Token方案

实现方式:

class DatabaseToken {
    private $db;
    private $table = 'user_tokens';

    public function createToken($userId, $clientInfo = []) {
        $token = bin2hex(random_bytes(32));
        $expiresAt = date('Y-m-d H:i:s', time() + 3600);

        $this->db->prepare("
            INSERT INTO {$this->table} 
            (user_id, token, expires_at, client_info, created_at) 
            VALUES (?, ?, ?, ?, NOW())
        ")->execute([
            $userId, 
            $token,
            $expiresAt,
            json_encode($clientInfo)
        ]);

        return $token;
    }

    public function validateToken($token) {
        $stmt = $this->db->prepare("
            SELECT * FROM {$this->table} 
            WHERE token = ? AND expires_at > NOW() AND revoked = 0
        ");
        $stmt->execute([$token]);

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    public function revokeToken($token) {
        $this->db->prepare("
            UPDATE {$this->table} SET revoked = 1 WHERE token = ?
        ")->execute([$token]);
    }
}

优点:

缺点:

4. 加密Token (自实现方案)

简单可控的自定义方案

实现方式:

class EncryptedToken {
    private $key;
    private $cipher = 'AES-256-GCM';

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

    public function createToken($data) {
        $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
        $data['exp'] = time() + 3600;
        $data['iat'] = time();

        $plaintext = json_encode($data);
        $ciphertext = openssl_encrypt(
            $plaintext,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        // Base64编码便于传输
        return base64_encode($iv . $tag . $ciphertext);
    }

    public function validateToken($token) {
        $decoded = base64_decode($token);

        $ivLength = openssl_cipher_iv_length($this->cipher);
        $tagLength = 16; // GCM标签长度

        $iv = substr($decoded, 0, $ivLength);
        $tag = substr($decoded, $ivLength, $tagLength);
        $ciphertext = substr($decoded, $ivLength + $tagLength);

        $plaintext = openssl_decrypt(
            $ciphertext,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        if ($plaintext === false) {
            return false;
        }

        $data = json_decode($plaintext, true);

        // 检查过期时间
        if (isset($data['exp']) && $data['exp'] < time()) {
            return false;
        }

        return $data;
    }
}

优点:

缺点:

方案对比

特性 JWT OAuth2 数据库Token 加密Token
状态 无状态 有状态 有状态 无状态
安全性 很高 取决于实现
性能
扩展性 很好 一般 一般
实现复杂度
适用场景 API、微服务 第三方授权、企业应用 Web应用、需精确控制 简单API、内部系统

选择建议

纯API项目 → 推荐 JWT 需要第三方授权 → 推荐 OAuth2 传统Web应用 → 推荐 数据库Token 或 Session 简单内部系统 → 推荐 加密Token

最佳实践补充

// 无论选择哪种方案都应考虑:
class TokenBestPractices {
    // 1. 使用HTTPS传输
    // 2. 设置合适的过期时间
    // 3. 实现Refresh Token机制
    // 4. 记录Token使用日志
    // 5. 提供Token撤销功能
    // 6. 防范CSRF攻击
    // 7. 定期更换密钥
}

根据具体需求选择合适的Token方案,并在项目中保持一致性。

相关推荐