如何使用 Azure Active Directory 认证和 Microsoft Graph 构建 Blazor Web 应用

英文原文:https://developer.microsoft.com/en-us/identity/blogs/how-to-build-a-blazor-web-app-with-azure-active-directory-authentication-and-microsoft-graph/

如果您是一个 .NET 开发者,你很可能听过过 Blazor 是一个最近的热门开发技术。Blazor 是一个使用 .NET Blazor 服务器来构建可交互客户端 Web 界面的框架。就是本文所专注的技术,提供了在 ASP.NET Core 应用中,在服务器端寄宿 Razor 组件的支持。UI 的更新通过 SignalR 连接进行。由于多数的应用都需要某些程度的验证和授权,这里将展示如何使用 Azure AD 实现验证的最佳方式,以及如何从 Microsoft Graph 获取数据。

先决条件

为了继续下面的演练,您需要最新版本的 NET Core 3.1 SDK, Visual Studio 2019 (可选,但是最好),并且拥有一个 Azure AD 的租户。如果你不能访问 Azure AD 租户,要么你可以免费注册一个 Microsoft 365 Developer program,或者创建一个免费的 Free Azure Trial 试用账号。

Blazor 与验证

如果你正在构建 Blazor (服务器端) 应用,那么我们有一些好消息。Visual Studio 和 CLI 模版支持开箱即用的验证支持。打开 Visual Studio,然后创建一个新的 Blazor 应用。我们将它命名为 "BlazorAppWithAuth",然后按照下面的动画进行。

通过选择工作或者学校账号验证选项,Visual Studio 将在 Azure AD 上创建适当的应用注册,并为 Blazor 应用配置开箱即用的验证所需的配置和代码。我们可以通过检查 appsettings.json 来确认。

并且,如果你到 Azure 门户的 Azure AD 注册页签中查看,还可以看到与 Visual Studio 中看到的信息想匹配的应用注册资料。

不需要写一行代码,我们的 Blazor 应用在用户访问任何页面之前,就可以提示用户。我们可以通过运行应用来快速测试该应用。在我们第一次访问该站点的时候,我们将被提示这些应用要求的 (默认) 权限,这里是读取用户的资料。

到了这一步,你可能认为我们的任务已经完成了,实际上,还有许多事情要做。首先,默认的模版使用了老式的,默认 v1 版本的 Azure AD 端点。如果你想知道为什么你应当使用 Microsoft identity platform 并使用 v2 版本的端点,你可以查看 Microsoft identity platform 文档

使用 Microsoft.Identity.Web 现代化验证

Build 2020 中,我们为 ASP.NET Core 3.1 (及后继版本) 宣布了一个新的验证和令牌管理库。新的库对复杂性进行了很棒的大量抽象,支持开发者只需要很少的代码就可以实现验证。而且,新库最大的优势是因为该库构建与 MSAL 之上,你不再需要使用两个单独的库来先进行验证,然后获得一个令牌来访问后端的 API。所以,让我们看一下如何迁移到这个最新的库上。

注意:Microsoft.Identity.Web 仍然在预览状态,它将很快发布

注意:现在 1.0 已经发布。发布时间:2020/10/1

注意:现在 1.1.0 已经发布,发布时间:Tuesday, October 6, 2020 (10/6/2020)

首先,我们需要下载这个新的 NuGet 包

  • Microsoft.Identity.Web - 1.1.0 已经发布
  • Microsoft.Identity.Web.UI - 1.1.0 已经发布

然后,我们需要修改几行代码来清除老的验证代码并切换到新的代码。

打开 Startup() 并替换代码,下面是原来的代码:

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options)); services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});

替换为:

services.AddMicrosoftWebAppAuthentication(Configuration);
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.AddMicrosoftIdentityUI();

使用 1.1 SDK 后,应该为:

services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.AddMicrosoftIdentityUI();

最后,我们需要确保我们的应用可以使用正确的 v2 版本端点来进行登录和登出。打开 LoginDisplay.razor 并进行如下的更新:

<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<a href="MicrosoftIdentity/Account/SignOut">Log out</a>
</Authorized>
<NotAuthorized>
<a href="MicrosoftIdentity/Account/SignIn">Log in</a>
</NotAuthorized>
</AuthorizeView>

你需要注意到,这里并没有特定的用来登录和登出的页面。相反,它们构建在 Microosft.Identity.Web.dll 内部。所以,在我们更新区域到 "MicrosoftIdentity" 的时候,不再需要其它的修改了。

当我们再次从 Visual Stuido 运行应用的时候,我们从 v2 中获得新的登录体验,例如无口令和多因子验证。最棒的是这些功能被设计为不需要修改任何代码,随着 Azure AD 的管理被配置为使用这些设置,所有的用户可以从更强的安全性中获益。

如你所见,使用很少的代码,我们可以借助于 Microsoft.Identity.Web 库基于 Azure AD 来验证用户。

从 Microsoft Graph 提取数据

Microsoft Graph 提供了大量的 API 来支持你基于用户自己的数据构建丰富的沉浸式的应用。在下面的步骤中,我们将拉取用户的电子邮件并将它们显示在应用内。为达到该目标,我们首先需要在 Azure AD 上扩展应用注册的权限,增加访问电子邮件数据的访问,然后我们需要在 Blazore 应用中添加一些代码来提取,并在其中的一个页面上显示数据。

Azure AD 门户

找到应用的注册,并进入 API 权限,选择添加新的权限,然后选择 Graph API,在这里,我们希望选择被代理权限,并选择 "Mail Read" 权限。

我们还需要创建一个用户密钥,因为我们的应用将需要一个验证令牌,和提取数据而不需要任何用户交互的方式。在同一个应用注册中,打开 Certificates 和 Secrets 页签,然后创建新的永不过期的密钥,如下所示:

确保你复制了密码,因为一旦你从该页面切换出去,你就再也不能访问它了。但是,如果需要的话,你总是可以重新创建它 - 这很简单且免费。

回到 Blazor 应用中,在 Visual Studio 中,我们首先需要在 appsettings.json 中添加客户密钥。在 AzureAD

的配置节,我们必须添加如下的行:

“ClientSecret”: “<your secret>”

在 Startup.cs 文件中,我们需要更新代码以确保使用正确的权限获取了适当的访问令牌,并将它保存在缓存中,以便我们在后继的应用中使用它访问 Microsoft Graph。我们将添加 HttpClient 到我们的服务管线中,来支持我们随后有效的发出 HTTP 调用到 Microsoft.Graph。

services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi( new string[] { "User.Read", "Mail.Read" })
.AddInMemoryTokenCaches(); services.AddHttpClient();

然后,我们需要更新在 FetchData.razor 页面中的代码来获取我们的电子邮件数据,来替代默认的天气数据。下面的代码包含了所有我们需要获取电子邮件并显示在页面上的代码。

@page "/fetchdata"

@inject IHttpClientFactory HttpClientFactory
@inject Microsoft.Identity.Web.ITokenAcquisition TokenAcquisitionService <h1>Weather forecast</h1> <p>This component demonstrates fetching data from a service.</p> @if (messages == null)
{
<p><em>Loading...</em></p>
}
else
{
<h1>Hello @userDisplayName !!!!</h1> <table class="table">
<thead>
<tr>
<th>Subject</th>
<th>Sender</th>
<th>Received Time</th>
</tr>
</thead>
<tbody>
@foreach (var mail in messages)
{
<tr>
<td>@mail.Subject</td>
<td>@mail.Sender</td>
<td>@mail.ReceivedTime</td>
</tr>
}
</tbody>
</table>
}
@code { private string userDisplayName;
private List<MailMessage> messages = new List<MailMessage>(); private HttpClient _httpClient; protected override async Task OnInitializedAsync()
{
_httpClient = HttpClientFactory.CreateClient(); // get a token
var token = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "User.Read", "Mail.Read" }); // make API call
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var dataRequest = await _httpClient.GetAsync("https://graph.microsoft.com/beta/me"); if (dataRequest.IsSuccessStatusCode)
{
var userData = System.Text.Json.JsonDocument.Parse(await dataRequest.Content.ReadAsStreamAsync());
userDisplayName = userData.RootElement.GetProperty("displayName").GetString();
} var mailRequest = await _httpClient.GetAsync("https://graph.microsoft.com/beta/me/messages?$select=subject,receivedDateTime,sender&$top=10"); if (mailRequest.IsSuccessStatusCode)
{
var mailData = System.Text.Json.JsonDocument.Parse(await mailRequest.Content.ReadAsStreamAsync());
var messagesArray = mailData.RootElement.GetProperty("value").EnumerateArray(); foreach (var m in messagesArray)
{
var message = new MailMessage();
message.Subject = m.GetProperty("subject").GetString();
message.Sender = m.GetProperty("sender").GetProperty("emailAddress").GetProperty("address").GetString();
message.ReceivedTime = m.GetProperty("receivedDateTime").GetDateTime();
messages.Add(message);
}
}
} public class MailMessage
{
public string Subject;
public string Sender;
public DateTime ReceivedTime;
}
}

重新运行应用,并确保先登出当前的用户,因为当前的令牌没有包含正确的访问权限,并且我们已经修改了一些代码。你将会注意到再次登录的时候,我们的提示增加了新的访问权限,这意味着一切如我们所愿。现在,除了基本的用户资料数据,应该还可以请求访问我们的电子邮件数据。

在授权之后,我们被导航到了 "Fetch Data" 页面,可以看到一些电子邮件!

如果你正确的如上演练,你现在应该可以看到类似上面图示中的你的电子邮件数据了。

总结

新的 Microsoft.Identity.Web 在简化验证和令牌管理方面做了出色的改进,你现在就应该开始使用它,在开始之前,有些事情值得你关注:

  1. 与普通的支持动态/增加提醒的 Web 应用不同,在 Blazor 中,你需要在一开始为你的应用请求所有需要的权限。失败的话,将会导致 TokenAcruisition 方法不能根据新的权限验证用户。这是 Blazor 机制的一部分,所以在创建应用的时候要记住这一点。
  2. 不是自己处理 Microsoft Graph HTTP 请求,你应该借助于 Microsoft Graph SDK,它简化了与 Microsoft Graph 的交互并提供了所有你需要序列化和反序列的对象。但是,在本示例中,我们仅仅遵循了建议 1,因为我们仅仅发出一个 Microsoft Graph 调用。

最后,你可以在 GitHub 上找到本示例 Blazor 应用程序的可运行示例的所有的源代码

参考

如何使用 Azure Active Directory 认证和 Microsoft Graph 构建 Blazor Web 应用的更多相关文章

  1. 如何通过 PHP 获取 Azure Active Directory 令牌

    在调用 Azure Rest API 时,如果是属于 Azure Resource Manager 的 API,则需要使用 Azure Active Directory (Azure AD)认证获取令 ...

  2. Azure Active Directory中的特权身份管理如何运作?

    [TechTarget中国原创] 用户权限不是平等的.有些用户需要有大量权利和特权——通常这些都是管理员.企业在允许特权用户进行管理以及支持活动时,还需要意识到特权用户也有可能犯错.他们会犯错.他们可 ...

  3. SRV记录用来标识某台服务器使用了某个服务,常见于微软系统的目录管理——深入的话需要去折腾Azure Active Directory

    SRV记录 SRV记录 什么情况下会用到SRV记录? [SRV记录用来标识某台服务器使用了某个服务,常见于微软系统的目录管理] SRV记录的添加方式 A.主机记录处格式为:服务的名字.协议的类型 例如 ...

  4. Azure AD(五)使用多租户应用程序模式让任何 Azure Active Directory 用户登录

    一,引言 距离上次分享关于 “Azure AD" 的知识过去差不多2个多月了, 今天最近刚好也是学习,分享一下关于Azure AD 使用多租户应用程序模式让任何 Azure Active D ...

  5. 【Azure Developer】使用 adal4j(Azure Active Directory authentication library for Java)如何来获取Token呢

    问题描述 使用中国区的Azure,在获取Token时候,参考了 adal4j的代码,在官方文档中,发现了如下的片段代码: ExecutorService service = Executors.new ...

  6. 简化 Web 应用程序与 Windows Azure Active Directory、ASP.NET 和 Visual Studio 的集成

    大家好! 今天的博文深入讨论我们今天推出的开发人员工具和框架中的一些新功能.我们通过与 ASP.NET 和 Visual Studio 团队合作开发了一些重大的增强功能,让开发人员能够轻松使用 Win ...

  7. 移动服务和 Azure Active Directory 中基于角色的访问控制

    编辑人员注释:本文章由 Matthew Henderson撰写 去年 11月,我们发布了 Azure Active Directory (AAD) 预览版作为移动服务身份提供程序.此举旨在为企业开 ...

  8. Azure Active Directory document ---reading notes

    微软利用本地活动目录 Windows Server Active Directory 进行身份认证管理方面具有丰富的经验,现在这一优势已延伸基于云平台的Azure Active Directory.可 ...

  9. 使用 Azure Active Directory 管理 Azure 中的 HPC Pack 群集

    Microsoft HPC Pack 2016 支持在 Azure 中部署 HPC Pack 群集的管理员将其与 Azure Active Directory (Azure AD) 集成. 请按照本文 ...

随机推荐

  1. python中的运动控制函数

    运动控制函数:控制海龟走直线&走曲线 海龟向前行进,海龟走直线,参数d表示行进距离,也可以为负数,单位是像素 根据半径r绘制extent角度的弧形 r : 默认圆心在海龟左侧r 距离的位置 e ...

  2. redis哨兵机制--配置文件sentinel.conf详解

    转载自 https://blog.csdn.net/u012441222/article/details/80751390 Redis的哨兵机制是官方推荐的一种高可用(HA)方案,我们在使用Redis ...

  3. vue学习09 图片切换

    目录 vue学习09 图片切换 定义图片数组:imgList:[],列表数据使用数组保存 添加图片索引:index 绑定src属性:使用v-bind,v-bind指令可以设置元素属性,比如src 图片 ...

  4. java进阶(23)--List接口

    一.基本概念 1.有序可重复 2.有下标 3.包含ArraList.LinkedList.Vector   二.List中特有的方法 且常用 (以下军均为数组通用方法) 1.void add(int ...

  5. c#后台代码请求访问api接口

    前言:最近公司项目与外部api接口对接较多 ,写下自己的代码总结.介绍两种访问方式(HttpClient.HttpWebRequest) 一.HttpWebRequest 访问Api private ...

  6. 中秋国庆8天挑战赛 之 挑战8天掌握微信小程序

    中秋国庆8天挑战赛 挑战8天掌握微信小程序 当前学习进度: // 10.1​// 学习内容:​// 10.2​// 学习内容:​// 10.3​// 学习内容:​// 10.4​// 学习内容:​// ...

  7. 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)

    094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  8. 05 sublime环境配置及编译运行后输出中文乱码的解决

    编译后的乱码问题 编译后的输出:中文显示异常: 编译C出现乱码问题解决 解决思路:解决办法很简单,就是先设置文件编码为GBK格式,之后再输入中文文字,运行时的中文就不是乱码了. 首先,sublime中 ...

  9. arduino中SCoop库的简单应用案例

    转载:https://www.csdn.net/gather_27/MtTaggzsMDExMS1ibG9n.html arduino中SCoop库的简单应用案例首先这篇文章来在视频https://v ...

  10. 使用 .NET 进行游戏开发

    微软是一家综合性的网络公司,相信这点来说不用过多的赘述,没有人不知道微软这个公司,这些年因为游戏市场的回报,微软收购了很多的游戏公司还有独立工作室,MC我的世界就是最成功的的案例,现在市值是排在全世界 ...