本篇我们介绍设备码认证,并用我们的程序去实现设备码流程。
为什么要使用不同的流程?
身份认证和授权是需要解决的复杂问题,特别在我们包括多样化的方案和场景时,设备、网络和系统都会有所体现。
微软标识平台是Microsoft 365和Microsoft Graph的主要认证平台,实现了像OAuth 2.0和Open Id Connect这样的行业标准。
到目前为止,之前的文章都使用了一种认证:
- 加密客户端流:该解决方案依靠应用程序注册id和密钥对要执行的应用程序进行认证和授权。它假设你作为开发者、管理员甚至是组织,能够安全地存储密钥,且对运行环境有直接的控制权限。该解决方案很适合构建后台进程、API和类似的解决方案。
注意:加密客户端流配置为使用应用程序权限。这意味着其中只有当前应用程序所反映出的认证标识,而不具有当前调用API的用户信息。尽管这对于实现需要提权的模式或无人值守进程时是可行的,但如果我们构建的是最终用户访问的功能,这将迅速成为一个制约甚至是安全问题。
后续我们会介绍到OAuth 2.0隐式流:
- 该解决方案基于cookies和跳转来使认证和授权对最终用户近乎透明。你很可能已经猜到了,cookies和跳转在前端应用程序的浏览器上下文中工作得很好,但是它也需要具备比HTTP请求更多的东西——“高级HTTP客户端”的能力。
设备码流
设备码流是另外一种类型的认证流,是为本地被认为“不安全“的应用程序(桌面、移动端等)设计的。基本流程如下:
- 应用程序显示来自认证提供程序的链接和一个唯一代码。如Azure AD的https://microsoft.com/devicelogin。
- 用户打开浏览器,访问链接并输入代码。
- 认证提供程序帮助用户选择需求的帐户,同意访问应用。
- 用户关闭浏览器窗口。
- 认证提供程序向应用程序提供就绪状态的认证上下文。
该流的设计主要考虑了以下几个关键点:
- 浏览器通常已经经过认证提供程序的认证了。
- 用户通常不希望在一个应用程序的小浏览器窗口中反复输入凭据。
- 一些执行上下文无法显示浏览器窗口,尤其是Windows的一些版本、旧版的移动端应用等。
- 用户如果愿意,可以使用一个其他设备去进行认证序列。
注意:设备码流需要使用托管权限执行操作,如果想通过此种方式执行之前几篇文章中提到的操作,需要添加相应的托管权限。
练习
在本次练习中我们用代码实现设备码流。
Step 1. 更新应用程序权限
这次我们添加一个托管权限User.Read.All并批准。
Step 2. 启用应用程序对设备码流的支持
- 点击应用程序左侧菜单的Manifest。
- 将allowPublicClient属性设置为true。
- 点击保存。
Step 3. 在应用程序中实现设备码流
在Helpers文件夹中创建一个新类DeviceCodeFlowAuthorizationProvider.cs,并替换为以下代码,该类包含了在GraphServiceClient需要访问令牌时实现设备码流的代码:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Graph;
using Microsoft.Identity.Client;
namespace GraphDemo
{
public class DeviceCodeFlowAuthorizationProvider : IAuthenticationProvider
{
private readonly PublicClientApplication _application;
private readonly List<string> _scopes;
private string _authToken;
public DeviceCodeFlowAuthorizationProvider(PublicClientApplication application, List<string> scopes)
{
_application = application;
_scopes = scopes;
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
if (string.IsNullOrEmpty(_authToken))
{
var result = await _application.AcquireTokenWithDeviceCodeAsync(_scopes, callback => {
Console.WriteLine(callback.Message);
return Task.FromResult(0);
});
_authToken = result.AccessToken;
}
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", _authToken);
}
}
}
扩展Program类去使用这个新的认证流
在Program类的CreateAuthorizationProvider方法中,将最后两行替换为:
运行结果如下所示:
最新代码已上传,戳这里。
新公众号,还在慢慢完善,欢迎关注。