用于 C# (.NET) 中 OAuth 2.0 和 OpenID Connect 的 IdentityModel 库
在 .NET 平台上开发现代 Web 应用程序、移动客户端或服务器端 API 时,几乎总是需要与外部身份验证提供商(Google、GitHub、Microsoft 等)或您自己的授权服务器进行集成。IdentityModel 是一个轻量级但功能强大的 C# 库,它提供了一个便捷的 OAuth 客户端,用于处理 OAuth 2.0 和 OpenID Connect 协议。它实际上是 .NET 生态系统中实现授权流程的事实标准。
在本文中,我们将详细介绍如何使用 IdentityModel 创建 OAuth 客户端、获取访问令牌以及刷新令牌。代码示例将使用 C# (.NET 6+)。
安装与配置
首先,通过 NuGet 包管理器安装包:
dotnet add package IdentityModel或者通过包管理器控制台:
Install-Package IdentityModel安装后,您将可以访问 HttpClient 扩展方法、DiscoveryClient、TokenClient 类以及其他辅助工具。
基本场景:通过客户端凭证获取令牌
此流程用于服务器到服务器的身份验证,即客户端(您的应用程序)代表自身而非用户请求令牌。
OAuth 客户端配置示例:
using IdentityModel.Client;using System.Net.Http;using System.Threading.Tasks;
public async Task<string> GetAccessTokenAsync(){ var client = new HttpClient();
// 1. 从授权服务器获取发现文档 var disco = await client.GetDiscoveryDocumentAsync("https://your-auth-server.com"); if (disco.IsError) { throw new Exception($"获取发现文档时出错: {disco.Error}"); }
// 2. 使用 client_id 和 client_secret 请求令牌 var tokenResponse = await client.RequestClientCredentialsTokenAsync( new ClientCredentialsTokenRequest { Address = disco.TokenEndpoint, ClientId = "your-client-id", ClientSecret = "your-client-secret", Scope = "api1 api2" // 请求的权限范围 });
if (tokenResponse.IsError) { throw new Exception($"获取令牌时出错: {tokenResponse.Error}"); }
return tokenResponse.AccessToken;}在此示例中,我们使用了 IdentityModel.Client 命名空间中的扩展方法。该库会自动处理 JSON 序列化、标头和响应解析。
授权码流程(涉及用户交互)
对于具有用户界面的应用程序(ASP.NET Core MVC、Blazor、桌面应用),通常使用授权码。IdentityModel 可与 Microsoft.AspNetCore.Authentication.OpenIdConnect 集成,但也提供用于手动实现的底层工具。
重定向后使用授权码获取令牌的示例:
public async Task<TokenResponse> ExchangeCodeForTokenAsync(string authorizationCode, string redirectUri){ var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync("https://your-auth-server.com");
var tokenResponse = await client.RequestAuthorizationCodeTokenAsync( new AuthorizationCodeTokenRequest { Address = disco.TokenEndpoint, ClientId = "your-client-id", ClientSecret = "your-client-secret", Code = authorizationCode, RedirectUri = redirectUri });
return tokenResponse;}刷新令牌
访问令牌通常有效期较短(例如 1 小时)。