PHP如何创建和管理JWT令牌

JSON Web令牌(JWT)已成为Web开发中各方之间安全传输信息的流行方法。在本指南中,我们将探索在PHP中创建、验证和解码JWT令牌,而不依赖于外部库。我们将利用 hash_hmac 生成签名,利用 base64_encode/decode 进行编码和解码。

环境配置

在深入研究代码之前,请确保您的服务器上安装了PHP。此外,您可能希望使用Composer来管理依赖项。在这个例子中,我们将创建一个独立的类来处理JWT操作。

composer init
composer require guzzlehttp/guzzle

JWT 类

现在,让我们创建一个名为 Jwt 的类来封装JWT操作:

<?php
class Jwt
{
    /**string */
    private string $secretKey;
    
    /**
     * @param string $secretKey
     * @author Tinywan(ShaoBo Wan)
     */
    public function __construct(string $secretKey)
    {
        $this->secretKey = $secretKey;
    }

    /**
     * @desc create token
     * @param array $payload
     * @return string
     * @author Tinywan(ShaoBo Wan)
     */
    public function createToken(array $payload): string
    {
        // Implementation for creating JWT
    }
    
    /**
     * @desc validate token
     * @param string $token
     * @return bool
     * @author Tinywan(ShaoBo Wan)
    */
    public function validateToken(string $token): bool
    {
        // Implementation for validating JWT
    }
    
    /**
     * @desc decode token
     * @param string $token
     * @return array
     * @author Tinywan(ShaoBo Wan)
    */
    public function decodeToken(string $token): array
    {
        // Implementation for decoding JWT
    }
    // Helper functions for base64 URL encoding/decoding
}

创建JWT

让我们实现用于生成JWT的 createToken 方法:

/**
 * @desc create token
 * @param array $payload
 * @return string
 * @author Tinywan(ShaoBo Wan)
 */
public function createToken(array $payload): string
{
    $base64UrlHeader = $this->base64UrlEncode(json_encode([\\\"alg\\\" => \\\"HS256\\\", \\\"typ\\\" => \\\"JWT\\\"]));
    $base64UrlPayload = $this->base64UrlEncode(json_encode($payload));
    $base64UrlSignature = hash_hmac(\\\'sha256\\\', $base64UrlHeader . \\\'.\\\' . $base64UrlPayload, $this->secretKey, true);
    $base64UrlSignature = $this->base64UrlEncode($base64UrlSignature);
    return $base64UrlHeader . \\\'.\\\' . $base64UrlPayload . \\\'.\\\' . $base64UrlSignature;
}

/**
 * @desc base64_encode 编码
 * @param string $data
 * @return string
 * @author Tinywan(ShaoBo Wan)
 */
private function base64UrlEncode(string $data): string
{
    $base64 = base64_encode($data);
    $base64Url = strtr($base64, \\\'+/\\\', \\\'-_\\\');
    return rtrim($base64Url, \\\'=\\\');
}

/**
 * @desc base64_encode 解码
 * @param string $data
 * @return string
 * @author Tinywan(ShaoBo Wan)
 */
private function base64UrlDecode(string $data): string
{
    $base64 = strtr($data, \\\'-_\\\', \\\'+/\\\');
    $base64Padded = str_pad($base64, strlen($base64) % 4, \\\'=\\\', STR_PAD_RIGHT);
    return base64_decode($base64Padded);
}

验证JWT

现在,让我们实现用于验证JWT的 validateToken 方法:

/**
 * @desc validate token
 * @param string $token
 * @return bool
 * @author Tinywan(ShaoBo Wan)
 */
public function validateToken(string $token): bool
{
    list($base64UrlHeader, $base64UrlPayload, $base64UrlSignature) = explode(\\\'.\\\', $token);
    $signature = $this->base64UrlDecode($base64UrlSignature);
    $expectedSignature = hash_hmac(\\\'sha256\\\', $base64UrlHeader . \\\'.\\\' . $base64UrlPayload, $this->secretKey, true);

    return hash_equals($signature, $expectedSignature);
}

解码JWT

最后,让我们实现用于解码JWT的 decodeToken 方法:

/**
 * @desc decode token
 * @param string $token
 * @return array
 * @author Tinywan(ShaoBo Wan)
 */
public function decodeToken(string $token): array
{
    list(, $base64UrlPayload, ) = explode(\\\'.\\\', $token);
    $payload = $this->base64UrlDecode($base64UrlPayload);
    return json_decode($payload, true);
}

验证

<?php

require \\\'vendor/autoload.php\\\';

// Your secret key (keep this secure)
$secretKey = \\\'Tinywan2024040000011\\\';

// Create an instance of Jwt
$jwt = new \\\\Tinywan\\\\Jwt($secretKey);

// Create a JWT
$payload = [
    \\\"user_id\\\" => 2024,
    \\\"username\\\" => \\\"Tinywan\\\",
    \\\"exp\\\" => time() + 3600, // Token expiration time (1 hour)
];
$token = $jwt->createToken($payload);

echo \\\'JWT Token: \\\' . $token . PHP_EOL;

// Validate and decode the JWT
if ($jwt->validateToken($token)) {
    echo \\\'JWT is valid.\\\' . PHP_EOL;
    $decodedPayload = $jwt->decodeToken($token);
    echo \\\"Decoded Payload: \\\" . json_encode($decodedPayload, JSON_PRETTY_PRINT).PHP_EOL;
    var_dump(json_decode(json_encode($decodedPayload), true));
} else {
    echo \\\'JWT is invalid.\\\' . PHP_EOL;
}

输出

JWT Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyMDI0LCJ1c2VybmFtZSI6IlRpbnl3YW4iLCJleHAiOjE3MTI1ODcyNTN9.7agfeUJxj-iE0oevkf_lQwmYZOcCd7ORHWycDNv27_I
JWT is valid.
Decoded Payload: {
    \\\"user_id\\\": 2024,
    \\\"username\\\": \\\"Tinywan\\\",
    \\\"exp\\\": 1712587253
}
array(3) {
  [\\\"user_id\\\"]=>
  int(2024)
  [\\\"username\\\"]=>
  string(7) \\\"Tinywan\\\"
  [\\\"exp\\\"]=>
  int(1712587253)
}

在本例中,我们创建了一个JWT,其有效负载包含用户ID、用户名和过期时间。然后我们使用我们的 Jwt类验证和解码JWT。

源码地址:https://github.com/Tinywan/jwt

原创文章,作者:网络技术联盟站,如若转载,请注明出处:https://www.sudun.com/ask/49902.html

(0)
网络技术联盟站's avatar网络技术联盟站
上一篇 2024年5月12日 上午1:38
下一篇 2024年5月12日 上午1:40

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注