2024年,WinUI3 使用 AccountsSettingsPane 获取微软账户信息

背景介绍:UWP 应用可以使用 AccountsSettingsPane 调用系统 UI 实现授权登录功能,相比跳转到网页可以获得更流畅的体验。

动手写代码之前,看文档的介绍非常美好。只需要处理 WebAccountProvider 和 WebTokenRequest 对象就能完成授权登录,简直可以说是少有的清晰明了的文档。文档中还提供了 WebAccountManagement Sample,列举了多种授权用法。

真的动手开始接入的时候,问题接踵而至。使用官方文档提供的代码和 WebAccountManagement Sample 中的代码都不能成功获取授权。

文档中获取授权的核心逻辑分两段,首先在 AccountsSettingsPane 中配置微软账户的 WebAccountProvider ,然后创建 WebTokenRequest 通过 WebAccountProvider 请求 Token。

官方文档中的 GetMsaTokenAsync 方法是创建 WebTokenRequest 的方法,内容如下:

private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
	WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
	WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
}

执行后 result.ProviderError 值为 WebTokenRequestStatus.ProviderErrorresult.ResponseError.ErrorMessage 内提示 0x80070057 参数错误

类似的, WebAccountManagement Sample 中给出的代码为 RequestTokenAndSaveAccount

此时报错信息变成了 0x80860003 应用程序请求身份验证令牌被禁用或者配置错误

可以注意到二者的区别其实只有 clientId 参数不同。

通过多多多多多多方查阅资料,发现微软的授权体系一直在变,改名部立大功。而许多历史文档和问答都被微软删掉了,砍刀部立大功。

很久以前的 Live SDK 完全找不到文档了,相关的设置因为微软商店开发者后台变来变去也早已经废弃了,Live SDK 设置似乎在 Application Registration Portal 页面,可以找到一个隐藏的 check box,打勾之后没办法保存配置。这个页面有一个应用程序 ID ,传到上面的 api 里结果依旧失败。

Application Registration Portal 也已经废弃了,微软推荐使用 Microsoft AAD Registered Apps 。

经过观察和实践得知,某个时间之前创建的应用会在 Application Registration Portal 列表中展示,在此之后创建的应用需要在 Microsoft AAD Registered Apps 中进行相关配置。但微软并不会自动创建一个 Azure 账户,所以需要使用与 Partner Center 登录的同一个邮箱注册 Azure 账户,之后在 应用注册 功能的 个人帐户中的应用程序 列表中就能看到对应的应用了。

对于 Microsoft AAD Registered App 中自动创建的应用,它的 Client ID 与 Partner Center 中对应的应用的 MSA 应用 ID 是一致的,都是 GUID 格式,无需任何配置即可使用;

对于 Application Registration Portal 中的应用, MSA 应用 ID 为 16 位数字和大写字母组成的字符串,此类应用无法转移到 Microsoft AAD Registered App 中。微软的授权登录已经不支持这种 Client ID了,所以需要在 Microsoft AAD Registered App 中手动创建一个应用注册,并进行如 文档 所述的相关配置。

使用 Microsoft AAD Registered App 中应用的 Client ID,运行代码结果依旧失败。

注意

创建应用注册时,受支持的账户类型一定要选第三项 任何组织目录(任何 Microsoft Entra ID 租户 - 多租户)中的帐户和个人 Microsoft 帐户(例如 Skype、Xbox) ,否则将不能使用未在"目录"中配置过的账户获得授权,并且应用注册的管理页面 没有任何 UI 选项 可以修改这个配置,唯一的解决方法是在应用注册的清单页面做如下配置

//...
"signInAudience": "AzureADandPersonalMicrosoftAccount",
//...
"api": {
    //... 
    "requestedAccessTokenVersion": 2,
    //...
},
//...

这时我注意到微软提供了一个 Microsoft Entra ID 的授权库

Microsoft.Identity.Client
Microsoft.Identity.Client.Broker

使用 文档 中的 BrokerOptions(BrokerOptions.OperatingSystems.Windows) 配置能成功调起系统的账户授权窗口,并且能完成授权拿到用户信息和令牌,但又不想引入额外依赖,故而抓包看了一下请求。

根据抓包的结果,在多次尝试之后找到了正确配置 WebTokenRequest 的方法:

var webTokenRequest = new WebTokenRequest(provider, scope: "User.Read openid profile", clientId);

webTokenRequest.Properties.Add("resource", "https://graph.microsoft.com");
webTokenRequest.Properties.Add("api-version", "2.0");
webTokenRequest.Properties.Add("oauth2_batch", "1");

此处 clientId 是 Microsoft AAD Registered Apps 中给出的 应用程序(客户端) ID ,而且注意到 scope 传入 User.Read openid profile 时, result.ResponseData[0].Token 的值为 x-www-form-urlencoded 格式的数据,可以手动解析出 access_token 字段;而 scope 仅传入 User.Read 时, result.ResponseData[0].Token 无任何前后缀,是完整的令牌。建议和 Microsoft.Identity.Client 库保持一致,传入 User.Read openid profile

至此,我们已经可以从系统的 AccountsSettingsPane 获取到个人微软账户的 access token 了。

最后提供一套简单的 Win32 应用获取 token 和用户信息的代码:
https://gist.github.com/cnbluefire/4721d8bcf90773bd1bce1344d33f7e7c

posted on 2024-12-19 22:38  叫我蓝火火  阅读(33)  评论(0编辑  收藏  举报

导航