C# 命令行应用使用 MSAL 和 Web Account Manager 机制验证用户身份
工作场景通常需要有身份认证机制保护的 API,客户端在调用这些 API 之前,就需要先进行身份验证,然后使用身份验证得到的 Access Token 去访问这些 API。这篇文章告诉你如何让控制台应用进行交互式身份验证,然后请求受保护的 API。
场景描述
见文档 Desktop app that calls a web API on behalf of a signed-in user
在 EntraId 中创建应用注册
概念和解释见相关文档
详细步骤如下
- 进入 Azure Portal
- 进入 Microsoft Entra ID
- 左侧导航栏找到 App registrations。可能需要展开 Manage 才能看到,如果还是看不到,需要管理员在 Entra ID Portal 里面配置一下。
- New registration
- 给个名字,剩下全都默认,然后注册即可
- 找到你刚写的 app 名字,点进去
- 记下来 Application (client) ID 和 Directory (tenant) ID,之后在代码中要用
- 展开左边 Manage,点 Authentication
- Add a platform,选 Mobile and desktop applications
- 在 Redirect URIs 里面添加自定义 URL: ms-appx-web://microsoft.aad.brokerplugin/
。这里 client id 就是前面记下来的 Application (client) ID。 - 保存
应用程序
新建一个 C# Console App,添加包
<PackageReference Include="Microsoft.Graph" Version="5.55.0" /> |
编辑 .csproj
文件
- 将
TargetFramework
里面的net8.0
改成net8.0-windows
- 在
PropertyGroup
里面增加<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
,Interop 获取 Console Window native handle 的时候用
辅助类 Interop
这个类用于获取当前窗口(即便是 Console App)的 Windows native 句柄,Web Account Manager 需要用到这个。
using System.Runtime.InteropServices; |
配置 Client
ClientId 和 TenantId 就是之前在注册 Application 的时候记下来的两条数据。原则上应该从配置文件里读,这里为了简化示例就硬编码进来了。如果你用的不是 Azure 公有云,而是国家云或者世纪互联什么的,需要调整 AzureCloudInstance.AzurePublic
这个参数。
var scopes = new[] { "User.Read" }; |
如果对 Public Client 的概念感兴趣可以看文档 Public client and confidential client applications。
使用 Client 认证用户身份
IEnumerable<IAccount> accounts = await app.GetAccountsAsync(); |
result
里面包含 AccessToken
可以用于访问受保护的 API,但是需要注意,这个 Token 是有过期时间限制的,过期之后需要再次获取。所以简单来说,每次你需要用 Token 的时候,都需要走一遍上面的流程。这个流程貌似(我没试验过)会在本地 cache Token,并且检查过期,见文档 Get a token from the token cache using MSAL.NET — Desktop, command-line, and mobile applications。
使用 AccessToken 访问受保护的 API
这里以 Microsoft Graph RESTful API 为例,其他应用大同小异。
HttpClient httpClient = new() |
参考资料
Using MSAL.NET with Web Account Manager (WAM) 注意,截止至成文时这个文档的例子走不通(2024 年 6 月 4 日),已经反馈。