使用 JSON WEB 令牌 (JWT) 对 .NET GITHUB 应用进行身份验证

作者:微信公众号:【架构师老卢】
1-26 19:56
164

概述:该文章描述了从 .NET 中的 RSA 私钥 PEM 文件生成应用程序 JWT。我们使用令牌对发送到 GitHub REST API 的请求进行身份验证。下一步是生成一个令牌,以开始在特定安装中执行操作。这是未来帖子的主题。

在这篇文章中,我将介绍创建和签署 JSON Web 令牌(此处缩写为 JWT)所需的步骤,以验证使用 .NET 构建的 GitHub 应用程序。

我想提前明确指出,我正在边走边学,同时尝试一个爱好项目来开发 GitHub 应用程序。我使用的一些方法可能不是最有效的,甚至不是最正确的。这不是生产就绪的代码,但希望它是一个很好的起点。

我们需要做的第一件事是在 GitHub.com 的“开发人员设置”GitHub Apps 页面上创建一个 GitHub 应用程序。

我不会在这里介绍创建应用程序的具体细节,因为它略微超出了我计划涵盖的范围。完成所有必填字段并提交创建 GitHub 应用程序表单后,系统将提示您创建私钥。您可以随时执行此操作,但必须完成此步骤才能开始进行身份验证。

点击按钮生成私钥后,将创建密钥,并自动下载PEM文件。此文件包含 RSA 私钥,我们进行身份验证时需要该私钥。当然,您应该确保此文件的安全,因为它提供对 GitHub 应用程序的任何安装的完全访问权限。对于此示例,我们将在本地和开发过程中使用它,但你强烈建议考虑将其存储在安全的位置,例如 Azure KeyVault。

下载文件后,我们就可以创建一个简单的 GitHub 应用程序了。在此示例中,我将从 .NET 8 控制台应用开始,使用顶级语句。

首先,我们将为一个库添加一个 NuGet 包,我们将使用该库创建 JWT 来验证我们对 GitHub REST API 的请求。

我们现在可以进入代码了。对于我们将要访问的命名空间,我们需要几个 using 指令。
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;

下一步是创建用于对 JWT 进行签名的签名凭据。JWT 必须使用 RS256 算法进行签名。此步骤的代码如下:

const string pemFilePath = "C:\\dotnet-sample-app.2024-01-12.private-key.pem";
 
var keyText = await File.ReadAllTextAsync(pemFilePath);
var rsa = RSA.Create();
rsa.ImportFromPem(keyText);
 
var signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);

在上面的代码中,我们定义了保存 RSA 私钥的 PEM 文件的路径和文件名。然后,代码从 PEM 文件中读取文本。我们创建一个 RSA 算法的实例,然后从 PEM 文件文本导入密钥。然后,我们可以创建所需的 SigningCredentials 实例。

下一步是创建已签名的 JWT,以对 GitHub REST API 的请求进行身份验证。

var jwtSecurityTokenHandler = new JwtSecurityTokenHandler { SetDefaultTimesOnTokenCreation = false };
 
var now = DateTime.UtcNow.AddSeconds(-60);
 
var jwt = jwtSecurityTokenHandler.CreateToken(new SecurityTokenDescriptor
{
    Issuer = "123456",
    Expires = now.AddMinutes(10),
    IssuedAt = now,
    SigningCredentials = signingCredentials
});

在前面的代码中,我们创建了一个可用于创建 JWT 的 JwtSecurityTokenHandler。我们将 SetDefaultTimesOnTokenCreation 属性设置为 false,因为我们将显式控制令牌的颁发时间和过期时间。我们将当前的 UTC 日期和时间存储到一个变量中。我们减去 60 秒,以防止运行代码的计算机和 GitHub 服务器之间的时钟漂移。

我们在处理程序上调用 CreateToken,传递一个定义令牌属性的 SecurityTokenDescriptor。GitHub 文档描述了所需的属性。我们必须包含颁发者,这是我们唯一的应用程序 ID,可在 GitHub 应用程序设置页面上找到。我们将此令牌的过期时间设置为 10 分钟(减去 60 秒),这是 GitHub 允许的最大值。我们使用分配给“now”变量的值设置“IssuedAt”属性。最后,我们必须附上我们的签名凭据。此方法以字符串形式返回 JWT。

为了结束此示例,我们向 GitHub REST API 发送请求。我们可以选择使用像 OktoKit 这样的库,它提供了一个类型化客户端,用于以编程方式与 GitHub API 进行交互。为了演示这将代表我们做什么,我将手动创建一个请求。

var client = new HttpClient() { BaseAddress = new Uri("https://api.github.com") };
 
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", jwt);
 
client.DefaultRequestHeaders.UserAgent.ParseAdd("Sample-GitHubApp/1.0.0");
 
var response = await client.GetAsync("/app/installations");
 
Debug.Assert(response.IsSuccessStatusCode);

上面的代码创建一个 HttpClient 实例,将基址设置为 REST API 根 URL。然后,我们在客户端上设置两个默认标头,这些标头将应用于所有请求。第一个使用我们的 JWT 添加持有者授权令牌。第二个添加用户代理。GitHub API 要求所有请求都必须包含此标头。

然后,我们对“/app/installations”路径执行 GET 请求。终结点返回应用程序的任何安装列表。由于这是一个新应用程序,尚未安装,因此这将是一个空数组。只要我们得到一个 200 成功状态代码,我们就可以得出结论,我们已经成功使用 API 进行了身份验证。

注意:请记住,JWT 将在创建后 9 分钟过期,因此对于将来的请求,您可能需要重新生成它。

该文章描述了从 .NET 中的 RSA 私钥 PEM 文件生成应用程序 JWT。我们使用令牌对发送到 GitHub REST API 的请求进行身份验证。下一步是生成一个令牌,以开始在特定安装中执行操作。这是未来帖子的主题。

阅读排行