使用 PHP 验证令牌 ID 和访问令牌

问题描述 投票:0回答:2

如何在 PHP 中使用 OPENID,而不使用库?

我使用的是 Twitch OAuth2.0,在构建身份验证后,我得到了“id_token”和“access_token”。

如何使用 PHP 验证 id_token 和 access_token 来获取代码?

php oauth oauth-2.0 openid lib
2个回答
2
投票

ID Token是一种JWT。 JWT 是 JWSJWE 的一种。以下为相关规格。

如果您想在不使用库的情况下验证 ID 令牌,那么第一步,您必须了解规范。然后,使用 PHP 标准函数进行解码、解密和验证签名等所有操作。

注意:无论ID Token是否加密,都会附有签名。要验证签名,如果签名的算法是非对称的,则必须获取与签名所用私钥相对应的公钥。

另一方面,访问令牌的格式因实现而异。


0
投票

它可能无法完全回答问题。 我仔细研究了它,并试图找到一个快速而小的代码来完成它。 我需要帮助找到简单的例子。我自己想出来了,想在这里分享。

我将在此处展示的代码仅使用一个库来生成零件。

该示例可与 Google 或 Microsoft 一起使用。

第一部分是存储您的客户端 ID、孩子和证书 URL。

<?php

class AuthConstants
{
    const GOOGLE_KID = 'WRITE_HERE_THE_KID';
    const GOOGLE_CLIENT_ID = 'WRITE_HERE_YOUR_CLIENT_ID';
    const GOOGLE_CERTS_URL = 'https://www.googleapis.com/oauth2/v3/certs';
    const MICROSOFT_KID = 'WRITE_HERE_THE_KID';
    const MICROSOFT_CLIENT_ID = 'WRITE_HERE_YOUR_CLIENT_ID';
    const MICROSOFT_CERTS_URL = 'https://login.microsoftonline.com/common/discovery/v2.0/keys';
}

一些帮手:

<?php
class CommonHelpers {

    public static function base64_url_decode($arg)
    {
        $res = $arg;
        $res = str_replace('-', '+', $res);
        $res = str_replace('_', '/', $res);
        switch (strlen($res) % 4) {
            case 0:
                break;
            case 2:
                $res .= "==";
                break;
            case 3:
                $res .= "=";
                break;
            default:
                break;
        }
        $res = base64_decode($res);
        return $res;
    }

}

以及带有逻辑的

IdToken
类来验证它

<?php

require_once 'vendor/autoload.php';

use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Math\BigInteger;

class IdToken
{
    private ?string $id_token;
    public array $headers;
    public array $claims;

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

    public function load_and_validate(): bool
    {
        $token_arr = explode('.', $this->id_token);
        $headers_enc = $token_arr[0];
        $claims_enc = $token_arr[1];

        $this->headers = json_decode(CommonHelpers::base64_url_decode($headers_enc), TRUE);
        $this->claims = json_decode(CommonHelpers::base64_url_decode($claims_enc), TRUE);

        if (time() > $this->claims['exp'])
            return false;  // The token expired

        $certs_url = self::get_validated_certs_url();
        if (!$certs_url)
            return false;

        $public_key = self::generate_public_key($certs_url);

        $token_sig_enc = $token_arr[2];
        $signature = CommonHelpers::base64_url_decode($token_sig_enc);

        $token_valid = openssl_verify($headers_enc . '.' . $claims_enc, $signature, $public_key, OPENSSL_ALGO_SHA256);
        return $token_valid == 1;
    }


    function get_validated_certs_url(): ?string
    {
        $kid = $this->headers['kid'];
        if (!$kid)
            return null;

        $aud = $this->claims['aud'];
        if (!$aud)
            return null;

        if ($kid === AuthConstants::GOOGLE_KID && $aud === AuthConstants::GOOGLE_CLIENT_ID)
            return AuthConstants::GOOGLE_CERTS_URL;

        if ($kid === AuthConstants::MICROSOFT_KID && $aud === AuthConstants::MICROSOFT_CLIENT_ID)
            return AuthConstants::MICROSOFT_CERTS_URL;

        return null;
    }


    function generate_public_key($certs_url)
    {
        $publicKeys = json_decode(file_get_contents($certs_url));

        $keyId = $this->headers['kid'];

        $publicKey = null;
        foreach ($publicKeys->keys as $key) {
            if ($key->kid == $keyId) {
                $publicKey = $key;
                break;
            }
        }

        if (!$publicKey)
            return null; // Unable to find public key

        $modulus = $publicKey->n;
        $exponent = $publicKey->e;

        $key = PublicKeyLoader::load([
            'n' => new BigInteger(CommonHelpers::base64_url_decode($modulus), 256),
            'e' => new BigInteger(CommonHelpers::base64_url_decode($exponent), 256),
        ]);
        $formattedPublicKey = $key->toString('PKCS8');
        if (!is_string($formattedPublicKey)) {
            return null; // 'Failed to initialize the key'
        }

        return $formattedPublicKey;
    }


}

您需要在

IdToken.php
所在的位置运行此命令:

composer require phpseclib/phpseclib:~3.0

要安装 Composer,请参阅:https://getcomposer.org/doc/00-intro.md

要验证 id_token,请调用:

$id_token = "eyj................" // replace this line with real id_token
$id_token = new IdToken($id_token);
$is_valid = $id_token->load_and_validate();
© www.soinside.com 2019 - 2024. All rights reserved.