教程:创建使用 Microsoft 标识平台进行身份验证的 Blazor Server 应用Tutorial: Create a Blazor Server app that uses the Microsoft identity platform for authentication

Blazor 服务器在 ASP.NET Core 应用中添加了对在服务器上托管 Razor 组件的支持。Blazor Server provides support for hosting Razor components on the server in an ASP.NET Core app. 在本教程中,你将了解如何使用 Microsoft 标识平台在 Blazor Server 应用中实施身份验证以及通过 Microsoft Graph 检索数据。In this tutorial, you learn how to implement authentication and retrieve data from Microsoft Graph in a Blazor Server app with the Microsoft identity platform.

在本教程中,你将了解如何执行以下操作:In this tutorial, you learn how to:

  • 创建配置为使用 Azure Active Directory (Azure AD) 进行身份验证的新 Blazor Server 应用。Create a new Blazor Server app configured to use Azure Active Directory (Azure AD) for authentication
  • 使用 Microsoft.Identity.Web 处理身份验证和授权Handle both authentication and authorization using Microsoft.Identity.Web
  • 通过受保护的 Web API Microsoft Graph 检索数据Retrieve data from a protected web API, Microsoft Graph

先决条件Prerequisites

在 Azure 门户中注册应用Register the app in the Azure portal

使用 Azure Active Directory (Azure AD) 进行身份验证的每个应用都必须注册到 Azure AD。Every app that uses Azure Active Directory (Azure AD) for authentication must be registered with Azure AD. 按照注册应用程序中的说明以及以下附加说明进行操作:Follow the instructions in Register an application with these additions:

  • 对于“支持的帐户类型”设置,请选择“仅限此组织目录中的帐户”。 For Supported account types , select Accounts in this organizational directory only .
  • 将“重定向 URI”下拉框的设置保留为“Web”并输入 https://localhost:5001/signin-oidcLeave the Redirect URI drop down set to Web and enter https://localhost:5001/signin-oidc. 在 Kestrel 上运行的应用的默认端口为 5001。The default port for an app running on Kestrel is 5001. 如果应用通过一个不同的端口提供,请指定该端口号而非 5001If the app is available on a different port, specify that port number instead of 5001.

在“身份验证” > “隐式授权”中,选中“访问令牌”和“ID 令牌”的复选框,然后选择“保存”按钮。In Authentication > Implicit grant , select the check boxes for Access tokens and ID tokens , and then select the Save button.

最后,因为应用调用了一个受保护的 API(在本例中为 Microsoft Graph),因此在请求访问令牌来调用该 API 时,它需要一个客户端机密来验证其身份。Finally, because the app calls a protected API (in this case Microsoft Graph), it needs a client secret in order to verify its identity when it requests an access token to call that API.

  1. 在同一应用注册中,在“管理”下选择“证书和机密”。Within the same app registration, under Manage , select Certificates & secrets .
  2. 创建一个永不过期的 新客户端机密Create a New client secret that never expires.
  3. 记下该机密的 ,你在下一步中将使用它。Make note of the secret's Value as you will use it in the next step. 离开此窗格后,将无法再访问它。You can’t access it again once you navigate away from this pane. 但是,你可以根据需要重新创建它。However, you can recreate it as needed.

使用 .NET CLI 创建应用Create the app using the .NET CLI

运行以下命令来下载适用于 Microsoft.Identity.Web 的模板,在本教程中将使用这些模板。Run the following command to download the templates for Microsoft.Identity.Web, which we will make use of in this tutorial.

dotnet new --install Microsoft.Identity.Web.ProjectTemplates::0.4.0-preview

然后,运行以下命令来创建应用程序。Then, run the following command to create the application. 将命令中的占位符替换为你的应用的概览页面中的正确信息,然后在命令行界面中执行该命令。Replace the placeholders in the command with the proper information from your app's overview page and execute the command in a command shell. 使用 -o|--output 选项指定的输出位置将创建一个项目文件夹(如果该文件夹不存在)并成为应用程序名称的一部分。The output location specified with the -o|--output option creates a project folder if it doesn't exist and becomes part of the app's name.

dotnet new blazorserver2 --auth SingleOrg --calls-graph -o {APP NAME} --client-id "{CLIENT ID}" --tenant-id "{TENANT ID}"
占位符Placeholder Azure 门户中的名称Azure portal name 示例Example
{APP NAME} BlazorSample
{CLIENT ID} 应用程序(客户端)IDApplication (client) ID 41451fa7-0000-0000-0000-69eff5a761fd
{TENANT ID} 目录(租户)IDDirectory (tenant) ID e86c78e2-0000-0000-0000-918e0565a45e

现在,在编辑器中导航到你的新 Blazor 应用,并在 appsettings.json 文件中添加客户端机密,替换文本“secret-from-app-registration”。Now, navigate to your new Blazor app in your editor and add the client secret to the appsettings.json file, replacing the text "secret-from-app-registration".

"ClientSecret": "xkAlNiG70000000_UI~d.OS4Dl.-Cy-1m3",

测试应用Test the app

现在可以生成并运行应用了。You can now build and run the app. 运行此模板应用时,必须使用 --framework 指定要运行的框架。When you run this template app, you must specify the framework to run using --framework. 本教程使用 .NET Core 3.1 SDK。This tutorial uses the .NET Core 3.1 SDK.

dotnet run --framework netcoreapp3.1

在浏览器中导航到 https://localhost:5001,使用 Azure AD 用户帐户登录,以查看运行的应用。In your browser, navigate to https://localhost:5001, and log in using an Azure AD user account to see the app running.

通过 Microsoft Graph 检索数据Retrieving data from Microsoft Graph

Microsoft Graph 提供了一系列 API,可用于访问用户的 Microsoft 365 数据。Microsoft Graph offers a range of APIs that provide access to your users' Microsoft 365 data. 通过使用 Microsoft 标识平台作为你的应用的标识提供者,你可以更轻松地访问此信息,因为 Microsoft Graph 直接支持 Microsoft 标识平台颁发的令牌。By using the Microsoft identity platform as the identity provider for your app, you have easier access to this information since Microsoft Graph directly supports the tokens issued by the Microsoft identity platform. 在本部分中,你将添加代码,以便在应用程序的“提取数据”页上显示已登录用户的电子邮件。In this section, you add code to display the signed in user's emails on the application's "fetch data" page.

在开始之前,请注销你的应用,因为你将对所需权限进行更改,并且你的当前令牌将不起作用。Before you start, log out of your app since you'll be making changes to the required permissions, and your current token won't work. 如果你尚未这样做,请再次运行应用,并在更新以下代码之前选择“注销”。If you haven't already, run your app again and select Log out before updating the code below.

现在,你将更新应用的注册和代码,以便拉取用户的电子邮件并在应用中显示这些消息。Now you will update your app's registration and code to pull a user's email and display the messages within the app. 若要实现此目的,请先在 Azure AD 中扩展应用注册权限,以启用对电子邮件数据的访问权限。To achieve this, first extend the app registration permissions in Azure AD to enable access to the email data. 然后,向 Blazor 应用添加代码来检索此数据并将其显示在其中一个页面上。Then, add code to the Blazor app to retrieve and display this data in one of the pages.

  1. 在 Azure 门户的“应用注册”中选择你的应用。In the Azure portal, select your app in App registrations .
  2. 在“管理”下选择“API 权限”。Under Manage , select API permissions .
  3. 选择“添加权限” > “Microsoft Graph” 。Select Add a permission > Microsoft Graph .
  4. 选择“委托的权限”,然后搜索并选择“Mail.Read”权限。Select Delegated Permissions , then search for and select the Mail.Read permission.
  5. 选择“添加权限”。Select Add permissions .

在 appsettings.json 文件中,更新你的代码,以便提取具有恰当权限的合适令牌。In the appsettings.json file, update your code so it fetches the appropriate token with the right permissions. 在“DownstreamAPI”下,在“user.read”作用域后添加“mail.read”。Add "mail.read" after the "user.read" scope under "DownstreamAPI". 这指定应用将请求对哪些作用域(或权限)进行访问。This is specifying which scopes (or permissions) the app will request access to.

"Scopes": "https://microsoftgraph.chinacloudapi.cn/user.read https://microsoftgraph.chinacloudapi.cn/mail.read"

接下来,更新 FetchData.razor 文件中的代码以检索电子邮件数据,而不是检索默认的(随机的)天气详细信息。Next, update the code in the FetchData.razor file to retrieve email data instead of the default (random) weather details. 将该文件中的代码替换为下面的代码:Replace the code in that file with the following:

@page "/fetchdata"

@inject IHttpClientFactory HttpClientFactory
@inject Microsoft.Identity.Web.ITokenAcquisition TokenAcquisitionService

<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[] { "https://microsoftgraph.chinacloudapi.cn/User.Read", "https://microsoftgraph.chinacloudapi.cn/Mail.Read" });

        // make API call
        _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
        var dataRequest = await _httpClient.GetAsync("https://microsoftgraph.chinacloudapi.cn/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://microsoftgraph.chinacloudapi.cn/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;
    }
}

启动应用。Launch the app. 你会注意到,系统将提示你输入新添加的权限,指示一切按预期方式工作。You’ll notice that you're prompted for the newly added permissions, indicating that everything is working as expected. 现在,除了基本的用户配置文件数据之外,应用还请求访问电子邮件数据。Now, beyond basic user profile data, the app is requesting access to email data.

在授权同意后,导航到“提取数据”页来阅读某封电子邮件。After granting consent, navigate to the "Fetch data" page to read some email.

最终应用的屏幕截图。它有一个显示为“Hello Nicholas”的标题,它显示了属于 Nicholas 的电子邮件列表。

后续步骤Next steps

通过我们的由多部分构成的方案系列了解如何调用和构建用于登录用户的 web 应用:Learn about calling building web apps that sign in users in our multi-part scenario series: