没有Firebase JWT的JSON网络令牌功能类

2023-06-01 00:00:00 功能 令牌 网络

我已经创建了一些关于如何使用 Firebase JWT 创建和使用 JSON Web 令牌的教程,但我决定尝试在没有框架的情况下只使用 PHP。

在本文中,您可以看到我如何创建自己的简单 JWT 生成器。


创建class

class JWT {
    private $headers;
    private $secret;
    public function __construct()
    {
        $this->headers = [
            'alg' => 'HS256', // we are using a SHA256 algorithm
            'typ' => 'JWT', // JWT type
            'iss' => 'jwt.local', // token issuer
            'aud' => 'example.com' // token audience
        ];
        $this->secret = 'thisIsASecret';
    }
}


生成令牌

在这个类中,我们将创建我们的生成函数。 

此函数将生成用于验证器的令牌。

public function generate(array $payload): string
{
    $headers = $this->encode(json_encode($this->headers)); // encode headers
    $payload["exp"] = time() + 60; // add expiration to payload
    $payload = $this->encode(json_encode($payload)); // encode payload
    $signature = hash_hmac('SHA256', "$headers.$payload", $this->secret, true); // create SHA256 signature
    $signature = $this->encode($signature); // encode signature
    return "$headers.$payload.$signature";
}


在我们的 generate 函数中,我们引用了一个 encode 函数。 

此函数将简单地对令牌使用的字符串进行 base64 编码。

private function encode(string $str): string
{
    return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); // base64 encode string
}

验证我们的令牌

在这个函数中,我们获取生成的令牌,并验证字符串、编码,最后是时间。 

我将它设置为 1 分钟,因此令牌将在 1 分钟后过期以确保它用于某个目的。

public function is_valid(string $jwt): bool
{
    $token = explode('.', $jwt); // explode token based on JWT breaks
    if (!isset($token[1]) && !isset($token[2])) {
        return false; // fails if the header and payload is not set
    }
    $headers = base64_decode($token[0]); // decode header, create variable
    $payload = base64_decode($token[1]); // decode payload, create variable
    $clientSignature = $token[2]; // create variable for signature
    if (!json_decode($payload)) {
        return false; // fails if payload does not decode
    }
    if ((json_decode($payload)->exp - time()) < 0) {
        return false; // fails if expiration is greater than 0, setup for 1 minute
    }
    if (isset(json_decode($payload)->iss)) {
        if (json_decode($headers)->iss != json_decode($payload)->iss) {
            return false; // fails if issuers are not the same
        }
    } else {
        return false; // fails if issuer is not set 
    }
    if (isset(json_decode($payload)->aud)) {
        if (json_decode($headers)->aud != json_decode($payload)->aud) {
            return false; // fails if audiences are not the same
        }
    } else {
        return false; // fails if audience is not set
    }
    $base64_header = $this->encode($headers);
    $base64_payload = $this->encode($payload);
    $signature = hash_hmac('SHA256', $base64_header . "." . $base64_payload, $this->secret, true);
    $base64_signature = $this->encode($signature);
    return ($base64_signature === $clientSignature);
}

class完整示例代码:

class JWT
{
    private $headers;
    private $secret;
    public function __construct()
    {
        $this->headers = [
            'alg' => 'HS256', // we are using a SHA256 algorithm
            'typ' => 'JWT', // JWT type
            'iss' => 'jwt.local', // token issuer
            'aud' => 'example.com' // token audience
        ];
        $this->secret = 'thisIsASecret'; // change this to your secret code
    }
    public function generate(array $payload): string
    {
        $headers = $this->encode(json_encode($this->headers)); // encode headers
        $payload["exp"] = time() + 60; // add expiration to payload
        $payload = $this->encode(json_encode($payload)); // encode payload
        $signature = hash_hmac('SHA256', "$headers.$payload", $this->secret, true); // create SHA256 signature
        $signature = $this->encode($signature); // encode signature
        return "$headers.$payload.$signature";
    }
    private function encode(string $str): string
    {
        return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); // base64 encode string
    }
    public function is_valid(string $jwt): bool
    {
        $token = explode('.', $jwt); // explode token based on JWT breaks
        if (!isset($token[1]) && !isset($token[2])) {
            return false; // fails if the header and payload is not set
        }
        $headers = base64_decode($token[0]); // decode header, create variable
        $payload = base64_decode($token[1]); // decode payload, create variable
        $clientSignature = $token[2]; // create variable for signature
        if (!json_decode($payload)) {
            return false; // fails if payload does not decode
        }
        if ((json_decode($payload)->exp - time()) < 0) {
            return false; // fails if expiration is greater than 0, setup for 1 minute
        }
        if (isset(json_decode($payload)->iss)) {
            if (json_decode($headers)->iss != json_decode($payload)->iss) {
                return false; // fails if issuers are not the same
            }
        } else {
            return false; // fails if issuer is not set 
        }
        if (isset(json_decode($payload)->aud)) {
            if (json_decode($headers)->aud != json_decode($payload)->aud) {
                return false; // fails if audiences are not the same
            }
        } else {
            return false; // fails if audience is not set
        }
        $base64_header = $this->encode($headers);
        $base64_payload = $this->encode($payload);
        $signature = hash_hmac('SHA256', $base64_header . "." . $base64_payload, $this->secret, true);
        $base64_signature = $this->encode($signature);
        return ($base64_signature === $clientSignature);
    }
}


结论

这是一个简单的项目,但按预期工作。

我过去使用过 Firebase JWT,但有时您只需要一个简单的解决方案,而无需导入整个库。

我希望这对您的下一个小项目有所帮助。您可以在我的 GitHub 上下载该课程或在 YouTube 上订阅更多教程。


转:

https://dev.to/thedevdrawer/json-web-tokens-without-firebase-jwt-3mop

相关文章