从0构建Oauth2Server服务 之Token 编解码

2023-12-05 0 579
目录
  • Token 编解码
    • JWT 访问令牌编码
    • 解码
    • Invalidating

从0构建Oauth2Server服务 之Token 编解码

Token 编解码

令牌提供了一种通过在令牌字符串本身中编码所有必要信息来避免将令牌存储在数据库中的方法。这样做的主要好处是 API 服务器能够验证访问令牌,而无需对每个 API 请求进行数据库查找,从而使 API 更容易扩展。

OAuth 2.0 Bearer Tokens 的好处是应用程序不需要知道您决定如何在您的服务中实现访问令牌。这意味着以后可以在不影响客户端的情况下更改您的实现。

如果您已经拥有一个可水平扩展的分布式数据库系统,那么您可能无法通过使用自编码令牌获得任何好处。事实上,如果您已经解决了分布式数据库问题,则使用自编码令牌只会引入新问题,因为使自编码令牌无效成为一个额外的障碍。

有很多方法可以对令牌进行自编码。您选择的实际方法只对您的实施很重要,因为令牌信息不会暴露给外部开发人员。

实现自编码令牌的最常见方法是使用 JWS 规范,创建要包含在令牌中的所有数据的 JSON 序列化表示,并使用只有授权服务器知道的私钥对生成的字符串进行签名.

JWT 访问令牌编码

下面的代码是用 PHP 编写的,并使用Firebase PHP-JWT库来编码和验证令牌。您需要包含该库才能运行示例代码实际上,授权服务器将有一个用于签署令牌的私钥,资源服务器将从授权服务器元数据中获取公钥以用于验证令牌。在这个例子中,我们每次都生成一个新的私钥,并在同一个脚本中验证令牌。实际上,您需要将私钥存储在某处以使用相同的密钥一致地签署令牌。

<?php
use \\Firebase\\JWT\\JWT;
# Generate a private key to sign the token.
# The public key would need to be published at the authorization
# server if a separate resource server needs to validate the JWT
$private_key = openssl_pkey_new([
\’digest_alg\’ => \’sha256\’,
\’private_key_bits\’ => 1024,
\’private_key_type\’ => OPENSSL_KEYTYPE_RSA
]);
# Set the user ID of the user this token is for
$user_id = \”1000\”;
# Set the client ID of the app that is generating this token
$client_id = \’https://example-app.com\’;
# Provide the list of scopes this token is valid for
$scope = \’read write\’;
$token_data = array(
# Issuer (the authorization server identifier)
\’iss\’ => \’https://\’ . $_SERVER[\’PHP_SELF\’],
# Expires At
\’exp\’ => time()+7200, // Valid for 2 hours
# Audience (The identifier of the resource server)
\’aud\’ => \’api://default\’,
# Subject (The user ID)
\’sub\’ => $user_id,
# Client ID
\’client_id\’ => $client_id,
# Issued At
\’iat\’ => time(),
# Identifier of this token
\’jti\’ => microtime(true).\’.\’.bin2hex(random_bytes(10)),
# The list of OAuth scopes this token includes
\’scope\’ => $scope
);
$token_string = JWT::encode($token_data, $private_key, \’RS256\’);

这将产生一个字符串,例如:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGhvcml6YXRpb24tc2VydmVyLmNvbS8iLCJleHAiOjE2MzczNDQ1NzIsImF1ZCI6ImFwaTovL2RlZmF1bHQiLCJzdWIiOiIxMDAwIiwiY2xpZW50X2lkIjoiaHR0cHM6Ly9leGFtcGxlLWFwcC5jb20iLCJpYXQiOjE2MzczMzczNzIsImp0aSI6IjE2MzczMzczNzIuMjA1MS42MjBmNWEzZGMwZWJhYTA5NzMxMiIsInNjb3BlIjoicmVhZCB3cml0ZSJ9.SKDO_Gu96WeHkR_Tv0d8gFQN1SEdpN8S_h0IJQyl_5syvpIRA5wno0VDFi34k5jbnaY5WHn6Y912IOmg6tMO91KlYOU1MNdVhHUoPoNUzYtl_nNab7Ywe29kxgrekm-67ZInDI8RHbSkL7Z_N9eZz_J8c3EolcsoIf-Dd5n9y_Y

该令牌由三个部分组成,以句点分隔。第一部分描述了使用的签名方法。第二部分包含令牌数据。第三部分是签名。

例如,此令牌的第一个组件是此 JSON 对象:

{
\”typ\”:\”JWT\”,
\”alg\”:\”RS256\”
}

第二个组件包含 API 端点处理请求所需的实际数据,例如用户标识和范围访问。

{
\”iss\”: \”https://authorization-server.com/\”,
\”exp\”: 1637344572,
\”aud\”: \”api://default\”,
\”sub\”: \”1000\”,
\”client_id\”: \”https://example-app.com\”,
\”iat\”: 1637337372,
\”jti\”: \”1637337372.2051.620f5a3dc0ebaa097312\”,
\”scope\”: \”read write\”
}

然后对这两个部分进行 base64 编码,JWT 库计算这两个字符串的 RS256 签名,然后用句点连接所有三个部分。

解码

可以使用相同的 JWT 库验证访问令牌。该库将同时对签名进行解码和验证,如果签名无效或令牌的到期日期已过,则抛出异常。

您需要与签署令牌的私钥相对应的公钥。通常,您可以从授权服务器的元数据文档中获取它,但在本例中,我们将从之前生成的私钥中派生出公钥。

注意:任何人都可以通过对令牌字符串的中间部分进行base64解码来读取令牌信息。因此,不要在令牌中存储私人信息或您不希望用户或开发人员看到的信息,这一点很重要。如果想隐藏token信息,可以使用JSON Web Encryptionspec对token中的数据进行加密。

$public_key = openssl_pkey_get_details($private_key)[\’key\’];
try {
# Note: You must provide the list of supported algorithms in order to prevent
# an attacker from bypassing the signature verification. See:
# https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
$token = JWT::decode($token_string, $jwt_key, [\’RS256\’]);
$error = false;
} catch(\\Firebase\\JWT\\ExpiredException $e) {
$token = false;
$error = \’expired\’;
$error_description = \’The token has expired\’;
} catch(\\Firebase\\JWT\\SignatureInvalidException $e) {
$token = false;
$error = \’invalid\’;
$error_description = \’The token provided was malformed\’;
} catch(Exception $e) {
$token = false;
$error = \’unauthorized\’;
$error_description = $e->getMessage();
}
if($error) {
header(\’HTTP/1.1 401 Unauthorized\’);
echo json_encode(array(
\’error\’=>$error,
\’error_description\’=>$error_description
));
die();
} else {
// Now $token has all the data that we encoded in it originally
print_r($token);
}

Invalidating

因为令牌可以在不进行数据库查找的情况下进行验证,所以在令牌过期之前无法使其失效。您需要采取额外的步骤来使自编码的令牌无效,例如临时存储已撤销令牌的列表,这是令jti牌中声明的一种用途。有关详细信息,请参阅刷新访问令牌。

以上就是从0构建Oauth2Server服务 之Token 编解码的详细内容,更多关于Oauth2Server Token编解码的资料请关注悠久资源网其它相关文章!

您可能感兴趣的文章:

  • 全面了解OAuth 2.0四种授权方式金三银四无惧面试
  • spring cloud 使用oauth2 问题汇总
  • Spring Cloud oauth2 认证服务搭建过程示例
  • 从0构建Oauth2Server服务之Refreshing-access-tokens

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悠久资源 PHP 从0构建Oauth2Server服务 之Token 编解码 https://www.u-9.cn/biancheng/php/94428.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务