从通用 Windows 平台应用程序 (XAML) 调用 Microsoft Graph APICall the Microsoft Graph API from a Universal Windows Platform application (XAML)

本指南介绍本机通用 Windows 平台 (UWP) 应用程序如何请求访问令牌,This guide explains how a native Universal Windows Platform (UWP) application can request an access token. 然后,应用程序调用 Microsoft Graph API。The application then calls the Microsoft Graph API. 本指南也适用于其他需要从 Microsoft 标识平台终结点请求访问令牌的 API。The guide also applies to other APIs that require access tokens from the Microsoft identity platform endpoint.

备注

本指南需要安装了通用 Windows 平台开发的 Visual Studio。This guide requires Visual Studio with Universal Windows Platform development installed. 有关如何下载和配置 Visual Studio 以开发通用 Windows 平台应用的说明,请参阅设置For instructions to download and configure Visual Studio to develop Universal Windows Platform apps, see Get set up.

备注

如果你不熟悉 Microsoft 标识平台,请从从通用 Windows 平台 (UWP) 应用程序调用 Microsoft Graph API 快速入门开始。If you're new to the Microsoft identity platform, start with the Call the Microsoft Graph API from a Universal Windows Platform (UWP) application quickstart.

本指南的工作原理How this guide works

显示本教程生成的示例应用的工作原理

本指南创建的示例 UWP 应用程序用于查询 Microsoft Graph API。This guide creates a sample UWP application that queries the Microsoft Graph API. 在此方案中,通过 Authorization 标头向 HTTP 请求添加令牌。For this scenario, a token is added to HTTP requests by using the Authorization header. Microsoft 身份验证库处理令牌获取和续订。Microsoft Authentication Library handles token acquisitions and renewals.

NuGet 包NuGet packages

本指南使用以下 NuGet 包:This guide uses the following NuGet package:

Library 说明Description
Microsoft.Identity.ClientMicrosoft.Identity.Client Microsoft 身份验证库Microsoft Authentication Library
Microsoft.GraphMicrosoft.Graph Microsoft Graph 客户端库Microsoft Graph Client Library

设置项目Set up your project

本部分逐步说明如何将 Windows 桌面 .NET 应用程序 (XAML) 与 Microsoft 登录集成。This section provides step-by-step instructions to integrate a Windows Desktop .NET application (XAML) with sign-in with Microsoft. 然后,该应用程序可以查询需要令牌的 Web API,例如 Microsoft Graph API。Then the application can query web APIs that require a token, such as the Microsoft Graph API.

本指南创建的应用程序显示用来查询 Microsoft Graph API 的按钮和用来注销的按钮。它还显示包含调用结果的文本框。This guide creates an application that displays a button that queries the Microsoft Graph API and a button to sign out. It also displays text boxes that contain the results of the calls.

备注

想要下载此示例的 Visual Studio 项目而不是创建它?Do you want to download this sample's Visual Studio project instead of creating it? 下载项目,并跳到应用程序注册步骤,在代码示例运行前对其进行配置。Download a project, and skip to the application registration step to configure the code sample before it runs.

创建应用程序Create your application

  1. 打开 Visual Studio,选择“新建项目”。Open Visual Studio, and select Create a new project.

  2. 在“创建新项目”中,为 C# 选择“空白应用(通用 Windows)”,然后选择“下一步”。 In Create a new project, choose Blank App (Universal Windows) for C# and select Next.

  3. 在“配置新项目”中为应用命名,然后选择“创建”。 In Configure your new project, name the app, and select Create.

  4. 如果出现提示,请在“新建通用 Windows 平台项目”中选择任意版本作为“目标”版本和“最低”版本,然后选择“确定”。 If prompted, in New Universal Windows Platform Project, select any version for Target and Minimum versions, and select OK.

    最低版本和目标版本

向项目添加 Microsoft 身份验证库Add Microsoft Authentication Library to your project

  1. 在 Visual Studio 中,选择“工具” > “NuGet 包管理器” > “包管理器控制台” 。In Visual Studio, select Tools > NuGet Package Manager > Package Manager Console.

  2. 在“包管理器控制台”窗口中复制并粘贴以下命令:Copy and paste the following commands in the Package Manager Console window:

    Install-Package Microsoft.Identity.Client
    Install-Package Microsoft.Graph
    

    备注

    首个命令将安装 Microsoft 身份验证库 (MSAL.NET)The first command installs Microsoft Authentication Library (MSAL.NET). MSAL.NET 获取、缓存和刷新用于访问受 Microsoft 标识平台保护的 API 的用户令牌。MSAL.NET acquires, caches, and refreshes user tokens that access APIs that are protected by the Microsoft identity platform. 第二个命令安装 Microsoft Graph .NET 客户端库,用于验证对 Microsoft Graph 的请求并调用该服务。The second command installs Microsoft Graph .NET Client Library to authenticate requests to Microsoft Graph and make calls to the service.

创建应用程序的 UICreate your application's UI

Visual Studio 创建 MainPage.xaml 作为项目模板的一部分。Visual Studio creates MainPage.xaml as a part of your project template. 打开此文件,然后将应用程序的“Grid”节点替换为以下代码:Open this file, and then replace your application's Grid node with the following code:

<Grid>
    <StackPanel Background="Azure">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="CallGraphButton" Content="Call Microsoft Graph API" HorizontalAlignment="Right" Padding="5" Click="CallGraphButton_Click" Margin="5" FontFamily="Segoe Ui"/>
            <Button x:Name="SignOutButton" Content="Sign-Out" HorizontalAlignment="Right" Padding="5" Click="SignOutButton_Click" Margin="5" Visibility="Collapsed" FontFamily="Segoe Ui"/>
        </StackPanel>
        <TextBlock Text="API Call Results" Margin="2,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="ResultText" TextWrapping="Wrap" MinHeight="120" Margin="5" FontFamily="Segoe Ui"/>
        <TextBlock Text="Token Info" Margin="2,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="TokenInfoText" TextWrapping="Wrap" MinHeight="70" Margin="5" FontFamily="Segoe Ui"/>
    </StackPanel>
</Grid>

使用 Microsoft 身份验证库获取用于 Microsoft Graph API 的令牌Use Microsoft Authentication Library to get a token for the Microsoft Graph API

本部分介绍如何使用 Microsoft 身份验证库获取用于 Microsoft Graph API 的令牌。This section shows how to use Microsoft Authentication Library to get a token for the Microsoft Graph API. 更改 MainPage.xaml.cs 文件。Make changes to the MainPage.xaml.cs file.

  1. MainPage.xaml.cs 中,添加以下引用:In MainPage.xaml.cs, add the following references:

    using Microsoft.Identity.Client;
    using Microsoft.Graph;
    using System.Diagnostics;
    using System.Threading.Tasks;
    
  2. 使用以下代码替换 MainPage 类:Replace your MainPage class with the following code:

    public sealed partial class MainPage : Page
    {
    
        //Set the scope for API call to user.read
        private string[] scopes = new string[] { "https://microsoftgraph.chinacloudapi.cn/user.read" };
    
        // Below are the clientId (Application Id) of your app registration and the tenant information.
        // You have to replace:
        // - the content of ClientID with the Application Id for your app registration
        private const string ClientId = "[Application Id pasted from the Azure portal]";
    
        private const string Tenant = "common"; // Alternatively "[Enter your tenant, as obtained from the Azure portal, e.g. kko365.partner.onmschina.cn]"
        private const string Authority = "https://login.partner.microsoftonline.cn/" + Tenant;
    
        // The MSAL Public client app
        private static IPublicClientApplication PublicClientApp;
    
        private static string MSGraphURL = "https://microsoftgraph.chinacloudapi.cn/v1.0/";
        private static AuthenticationResult authResult;
    
        public MainPage()
        {
            this.InitializeComponent();
        }
    
        /// <summary>
        /// Call AcquireTokenAsync - to acquire a token requiring user to sign in
        /// </summary>
        private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Sign in user using MSAL and obtain an access token for Microsoft Graph
                GraphServiceClient graphClient = await SignInAndInitializeGraphServiceClient(scopes);
    
                // Call the /me endpoint of Graph
                User graphUser = await graphClient.Me.Request().GetAsync();
    
                // Go back to the UI thread to make changes to the UI
                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    ResultText.Text = "Display Name: " + graphUser.DisplayName + "\nBusiness Phone: " + graphUser.BusinessPhones.FirstOrDefault()
                                      + "\nGiven Name: " + graphUser.GivenName + "\nid: " + graphUser.Id
                                      + "\nUser Principal Name: " + graphUser.UserPrincipalName;
                    DisplayBasicTokenInfo(authResult);
                    this.SignOutButton.Visibility = Visibility.Visible;
                });
            }
            catch (MsalException msalEx)
            {
                await DisplayMessageAsync($"Error Acquiring Token:{System.Environment.NewLine}{msalEx}");
            }
            catch (Exception ex)
            {
                await DisplayMessageAsync($"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}");
                return;
            }
        }
                /// <summary>
        /// Signs in the user and obtains an access token for Microsoft Graph
        /// </summary>
        /// <param name="scopes"></param>
        /// <returns> Access Token</returns>
        private static async Task<string> SignInUserAndGetTokenUsingMSAL(string[] scopes)
        {
            // Initialize the MSAL library by building a public client application
            PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
                .WithAuthority(Authority)
                .WithUseCorporateNetwork(false)
                .WithRedirectUri("https://login.partner.microsoftonline.cn/common/oauth2/nativeclient")
                 .WithLogging((level, message, containsPii) =>
                 {
                     Debug.WriteLine($"MSAL: {level} {message} ");
                 }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
                .Build();
    
            // It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.
            IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
            IAccount firstAccount = accounts.FirstOrDefault();
    
            try
            {
                authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
                                                  .ExecuteAsync();
            }
            catch (MsalUiRequiredException ex)
            {
                // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
                Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
    
                authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
                                                  .ExecuteAsync()
                                                  .ConfigureAwait(false);
    
            }
            return authResult.AccessToken;
        }
    }
    

以交互方式获取用户令牌Get a user token interactively

AcquireTokenInteractive 方法会生成提示用户登录的窗口。The AcquireTokenInteractive method results in a window that prompts users to sign in. 应用程序通常要求用户首次登录访问受保护的资源时采用交互方式。Applications usually require users to sign in interactively the first time to access a protected resource. 当用于获取令牌的无提示操作失败时,用户也可能需要登录。They might also need to sign in when a silent operation to acquire a token fails. 例如,当用户的密码过期时。An example is when a user's password has expired.

以无提示方式获取用户令牌Get a user token silently

AcquireTokenSilent 方法处理令牌获取和续订,无需进行任何用户交互。The AcquireTokenSilent method handles token acquisitions and renewals without any user interaction. AcquireTokenInteractive 首次运行并提示用户输入凭据后,请使用 AcquireTokenSilent 方法请求后续调用的令牌。After AcquireTokenInteractive runs for the first time and prompts the user for credentials, use the AcquireTokenSilent method to request tokens for later calls. 该方法以无提示方式获取令牌。That method acquires tokens silently. Microsoft 身份验证库处理令牌缓存和续订。Microsoft Authentication Library handles token cache and renewal.

最终,AcquireTokenSilent 方法会失败。Eventually, the AcquireTokenSilent method fails. 失败的原因包括用户已注销,或者已在另一设备上更改了密码。Reasons for failure include a user that signed out or changed their password on another device. Microsoft 身份验证库在检测到此问题需要交互式操作时,会引发 MsalUiRequiredException 异常。When Microsoft Authentication Library detects that the issue requires an interactive action, it throws an MsalUiRequiredException exception. 应用程序可以通过两种方式处理此异常:Your application can handle this exception in two ways:

  • 应用程序会立即调用 AcquireTokenInteractiveYour application calls AcquireTokenInteractive immediately. 此调用会导致系统提示用户进行登录。This call results in prompting the user to sign in. 通常将这个适合联机应用程序的方法用于没有脱机内容供用户使用的情况。Normally, use this approach for online applications where there's no available offline content for the user. 此引导式设置生成的示例遵循此模式。The sample generated by this guided setup follows the pattern. 首次运行示例时可以看到其正在运行。You see it in action the first time you run the sample.

    由于没有用户使用过该应用程序,因此 accounts.FirstOrDefault() 包含一个 null 值,并且引发 MsalUiRequiredException 异常。Because no user has used the application, accounts.FirstOrDefault() contains a null value, and throws an MsalUiRequiredException exception.

    此示例中的代码随后通过调用 AcquireTokenInteractive 来处理此异常。The code in the sample then handles the exception by calling AcquireTokenInteractive. 此调用会导致系统提示用户进行登录。This call results in prompting the user to sign in.

  • 应用程序会向用户提供视觉指示,要求用户登录。Your application presents a visual indication to users that they need to sign in. 然后,用户可以选择适当的时间进行登录。Then they can select the right time to sign in. 应用程序可以稍后重试 AcquireTokenSilentThe application can retry AcquireTokenSilent later. 当用户可以使用其他应用程序功能而不会出现中断时,请使用此方法。Use this approach when users can use other application functionality without disruption. 例如,当脱机内容在应用程序中可用时。An example is when offline content is available in the application. 在这种情况下,用户可以决定何时需要登录。In this case, users can decide when they want to sign in. 在出现网络暂时不可用的情况后,应用程序可以重试 AcquireTokenSilentThe application can retry AcquireTokenSilent after the network was temporarily unavailable.

通过从 SignInUserAndGetTokenUsingMSAL 方法获取令牌,来实例化 Microsoft Graph Service 客户端Instantiate the Microsoft Graph Service Client by obtaining the token from the SignInUserAndGetTokenUsingMSAL method

将以下新方法添加到 MainPage.xaml.csAdd the following new method to MainPage.xaml.cs:

      /// <summary>
     /// Sign in user using MSAL and obtain a token for Microsoft Graph
     /// </summary>
     /// <returns>GraphServiceClient</returns>
     private async static Task<GraphServiceClient> SignInAndInitializeGraphServiceClient(string[] scopes)
     {
         GraphServiceClient graphClient = new GraphServiceClient(MSGraphURL,
             new DelegateAuthenticationProvider(async (requestMessage) =>
             {
                 requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await SignInUserAndGetTokenUsingMSAL(scopes));
             }));

         return await Task.FromResult(graphClient);
     }

对受保护 API 进行 REST 调用的详细信息More information on making a REST call against a protected API

在此示例应用程序中,GetGraphServiceClient 方法通过使用访问令牌来实例化 GraphServiceClientIn this sample application, the GetGraphServiceClient method instantiates GraphServiceClient by using an access token. 然后,GraphServiceClient 用于从“me”终结点获取用户配置文件信息。Then, GraphServiceClient is used to get the user's profile information from the me endpoint.

添加方法以注销用户Add a method to sign out the user

若要注销用户,请将以下方法添加到 MainPage.xaml.csTo sign out the user, add the following method to MainPage.xaml.cs:

/// <summary>
/// Sign out the current user
/// </summary>
private async void SignOutButton_Click(object sender, RoutedEventArgs e)
{
    IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
    IAccount firstAccount = accounts.FirstOrDefault();

    try
    {
        await PublicClientApp.RemoveAsync(firstAccount).ConfigureAwait(false);
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            ResultText.Text = "User has signed out";
            this.CallGraphButton.Visibility = Visibility.Visible;
                this.SignOutButton.Visibility = Visibility.Collapsed;
            });
        }
        catch (MsalException ex)
        {
            ResultText.Text = $"Error signing out user: {ex.Message}";
        }
    }

备注

MSAL.NET 使用异步方法来获取令牌或操作帐户。MSAL.NET uses asynchronous methods to acquire tokens or manipulate accounts. 你需要在 UI 线程中支持 UI 操作。You need to support UI actions in the UI thread. 因此,需要进行 Dispatcher.RunAsync 调用,并在调用 ConfigureAwait(false) 之前采取预防措施。This is the reason for the Dispatcher.RunAsync call and the precautions to call ConfigureAwait(false).

有关注销的详细信息More information about signing out

SignOutButton_Click 方法从 Microsoft 身份验证库用户缓存中删除用户。The SignOutButton_Click method removes the user from the Microsoft Authentication Library user cache. 此方法有效地告知 Microsoft 身份验证库忘记当前用户。This method effectively tells Microsoft Authentication Library to forget the current user. 在未来发出获取令牌的请求时,必须采用交互方式才能成功。A future request to acquire a token succeeds only if it's interactive.

此示例中的应用程序支持单个用户。The application in this sample supports a single user. Microsoft 身份验证库支持用户通过多个帐户登录的方案。Microsoft Authentication Library supports scenarios where the user can sign in on more than one account. 用户在其中具有多个帐户的电子邮件应用程序就是一个示例。An example is an email application where a user has several accounts.

显示基本令牌信息Display basic token information

将以下方法添加到 MainPage.xaml.cs,以显示有关令牌的基本信息:Add the following method to MainPage.xaml.cs to display basic information about the token:

/// <summary>
/// Display basic information contained in the token. Needs to be called from the UI thread.
/// </summary>
private void DisplayBasicTokenInfo(AuthenticationResult authResult)
{
    TokenInfoText.Text = "";
    if (authResult != null)
    {
        TokenInfoText.Text += $"User Name: {authResult.Account.Username}" + Environment.NewLine;
        TokenInfoText.Text += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
    }
}

详细信息More information

通过 OpenID Connect 获取的 ID 令牌还包含与用户相关的一小部分信息。ID tokens acquired by using OpenID Connect also contain a small subset of information pertinent to the user. DisplayBasicTokenInfo 显示令牌中包含的基本信息。DisplayBasicTokenInfo displays basic information contained in the token. 该信息包含用户的显示名称和 ID。This information includes the user's display name and ID. 它还包含令牌到期日期,以及表示访问令牌本身的字符串。It also includes the expiration date of the token and the string that represents the access token itself. 如果多次选择“调用 Microsoft Graph API”按钮,将会发现后续请求重复使用了同一令牌。If you select the Call Microsoft Graph API button several times, you'll see that the same token was reused for later requests. 而且还会发现,在 Microsoft 身份验证库决定续订令牌时,过期日期也延长了。You can also see the expiration date extended when Microsoft Authentication Library decides it's time to renew the token.

显示消息Display message

将以下新方法添加到 MainPage.xaml.csAdd the following new method to MainPage.xaml.cs:

/// <summary>
/// Displays a message in the ResultText. Can be called from any thread.
/// </summary>
private async Task DisplayMessageAsync(string message)
{
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
         () =>
         {
             ResultText.Text = message;
         });
     }

注册应用程序Register your application

现在需注册应用程序:Now you need to register your application:

  1. 登录到 Azure 门户Sign in to the Azure portal.
  2. 选择“Azure Active Directory” > “应用注册”。 Select Azure Active Directory > App registrations.
  3. 选择“新注册”。Select New registration. 输入一个会显示给应用用户的有意义的应用程序名称,例如 UWP-App-calling-MSGraph。Enter a meaningful application name that will be displayed to users of the app, for example, UWP-App-calling-MSGraph.
  4. 支持的帐户类型下,选择“任何组织目录中的帐户”,然后选择“注册”以继续。Under Supported account types, select Accounts in any organizational directory, then select Register to continue.
  5. 在概览页上,找到并复制“应用程序(客户端) ID”值。On the overview page, find the Application (client) ID value and copy it. 返回到 Visual Studio,打开 MainPage.xaml.cs,将 ClientId 的值替换为该值。Go back to Visual Studio, open MainPage.xaml.cs, and replace the value of ClientId with this value.

为应用程序配置身份验证:Configure authentication for your application:

  1. 回到 Azure 门户中,在“管理”下选择“身份验证”。 Back in the Azure portal, under Manage, select Authentication.
  2. 在“重定向 URI” | “建议用于公共客户端(移动、桌面)的重定向 URI”部分中,选中 https://login.partner.microsoftonline.cn/common/oauth2/nativeclientIn the Redirect URIs | Suggested Redirect URIs for public clients (mobile, desktop) section, check https://login.partner.microsoftonline.cn/common/oauth2/nativeclient.
  3. 选择“保存” 。Select Save.

为应用程序配置 API 权限:Configure API permissions for your application:

  1. 在“管理”下选择“API 权限”。Under Manage, select API permissions.
  2. 选择“添加权限”,并确保已选择“Microsoft API” 。Select Add a permission, and then make sure that you've selected Microsoft APIs.
  3. 选择“Microsoft Graph”。Select Microsoft Graph.
  4. 选择“委托的权限”,搜索 User.Read 并验证是否已选择“User.Read”。Select Delegated permissions, search for User.Read, and verify that User.Read is selected.
  5. 如果进行了更改,请选择“添加权限”以保存所做的更改。If you made any changes, select Add permissions to save them.

在联盟域中启用集成身份验证(可选)Enable integrated authentication on federated domains (optional)

若要在与 Azure AD 联盟域配合使用的情况下启用集成的 Windows 身份验证,应用程序清单必须启用其他功能。To enable Integrated Windows authentication when it's used with a federated Azure AD domain, the application manifest must enable additional capabilities. 回到 Visual Studio 中的应用程序。Go back to your application in Visual Studio.

  1. 打开 Package.appxmanifestOpen Package.appxmanifest.

  2. 选择“功能”并启用以下设置:Select Capabilities, and enable the following settings:

    • 企业身份验证Enterprise Authentication
    • 专用网络(客户端和服务器)Private Networks (Client & Server)
    • 共享用户证书Shared User Certificates

重要

默认情况下,未为此示例配置集成 Windows 身份验证Integrated Windows authentication isn't configured by default for this sample. 请求Enterprise AuthenticationShared User Certificates功能的应用程序需要由 Windows 应用商店进行的更高级别的验证。Applications that request Enterprise Authentication or Shared User Certificates capabilities require a higher level of verification by the Windows Store. 此外,并非所有开发人员都希望执行更高级别的验证。Also, not all developers want to perform the higher level of verification. 仅当需要使用 Azure AD 联盟域进行集成 Windows 身份验证时,才启用此设置。Enable this setting only if you need Integrated Windows authentication with a federated Azure AD domain.

使用 WithDefaultRedirectURI() 的替代方法Alternate approach to using WithDefaultRedirectURI()

当前示例中使用了 WithRedirectUri("https://login.partner.microsoftonline.cn/common/oauth2/nativeclient") 方法。In the current sample, the WithRedirectUri("https://login.partner.microsoftonline.cn/common/oauth2/nativeclient") method is used. 若要使用 WithDefaultRedirectURI(),请完成以下步骤:To use WithDefaultRedirectURI(), complete these steps:

  1. 在 MainPage.XAML.cs 中,将 WithRedirectUri 替换为 WithDefaultRedirectUriIn MainPage.XAML.cs, replace WithRedirectUri with WithDefaultRedirectUri:

    当前代码Current code

    
    PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
        .WithAuthority(Authority)
        .WithUseCorporateNetwork(false)
        .WithRedirectUri("https://login.partner.microsoftonline.cn/common/oauth2/nativeclient")
        .WithLogging((level, message, containsPii) =>
         {
             Debug.WriteLine($"MSAL: {level} {message} ");
         }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
        .Build();
    
    

    更新的代码Updated code

    
    PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
        .WithAuthority("https://login.partner.microsoftonline.cn/common")
        .WithUseCorporateNetwork(false)
        .WithDefaultRedirectUri()
        .WithLogging((level, message, containsPii) =>
         {
             Debug.WriteLine($"MSAL: {level} {message} ");
         }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
        .Build();
    
  2. 通过在 MainPage.xaml.cs 中添加 redirectURI 字段并在其上设置断点,来查找应用的回调 URI:Find the callback URI for your app by adding the redirectURI field in MainPage.xaml.cs and setting a breakpoint on it:

    
    public sealed partial class MainPage : Page
    {
            ...
    
            string redirectURI = Windows.Security.Authentication.Web.WebAuthenticationBroker
                                .GetCurrentApplicationCallbackUri().ToString();
            public MainPage()
            {
                ...
            }
           ...
    }
    
    

    运行应用,然后在到达断点时,复制 redirectUri 的值。Run the app, and then copy the value of redirectUri when the breakpoint is hit. 该值应该类似于以下值:The value should look something similar to the following value:
    ms-app://s-1-15-2-1352796503-54529114-405753024-3540103335-3203256200-511895534-1429095407/

    然后,可以删除该代码行,因为只需要使用一次即可提取该值。You can then remove the line of code because it's required only once, to fetch the value.

  3. 在应用注册门户中,在“身份验证”窗格的“RedirectUri”中添加返回值 。In the app registration portal, add the returned value in RedirectUri in the Authentication pane.

测试代码Test your code

若要测试应用程序,请按“F5”键,在 Visual Studio 中运行项目。To test your application, select the F5 key to run your project in Visual Studio. 将显示主窗口:Your main window appears:

应用程序的用户界面

准备好测试后,选择“调用 Microsoft Graph API”。When you're ready to test, select Call Microsoft Graph API. 然后使用 Azure AD 组织帐户进行登录。Then use an Azure AD organizational account to sign in. 用户首次运行此测试时,应用程序会显示一个要求用户登录的窗口。The first time a user runs this test, the application displays a window asking the user to sign in.

首次登录应用程序时,会显示与下图类似的许可屏幕。The first time you sign in to your application, a consent screen appears similar to the following image. 选择“是”显式许可访问:Select Yes to explicitly consent to access:

访问许可屏幕

预期结果Expected results

“API 调用结果”屏幕上会显示 Microsoft 图形 API 调用返回的用户个人资料信息:You see user profile information returned by the Microsoft Graph API call on the API Call Results screen:

“API 调用结果”屏幕

“令牌信息”框中还会显示通过 AcquireTokenInteractiveAcquireTokenSilent 获得的令牌的相关基本信息:You also see basic information about the token acquired via AcquireTokenInteractive or AcquireTokenSilent in the Token Info box:

属性Property 格式Format 说明Description
Username user@domain.com 用于标识用户的用户名。The username that identifies the user.
Token Expires DateTime 令牌的过期时间。The time when the token expires. Microsoft 身份验证库通过根据需要续订令牌来延长到期日期。Microsoft Authentication Library extends the expiration date by renewing the token as necessary.

有关作用域和委派权限的详细信息More information about scopes and delegated permissions

Microsoft Graph API 需要 user.read 作用域来读取用户的配置文件。The Microsoft Graph API requires the user.read scope to read a user's profile. 默认情况下,在门户中注册的每个应用程序中,都会添加此作用域。This scope is added by default in every application that's registered in the Portal. Microsoft Graph 的其他 API 以及后端服务器的自定义 API 可能需要其他作用域。Other APIs for Microsoft Graph and custom APIs for your back-end server might require additional scopes. 例如,Microsoft Graph API 需要 Calendars.Read 作用域来列出用户的日历。For instance, the Microsoft Graph API requires the Calendars.Read scope to list the user's calendars.

若要在应用程序上下文中访问用户的日历,请将 Calendars.Read 委托权限添加到应用程序注册信息。To access the user's calendars in the context of an application, add the Calendars.Read delegated permission to the application registration information. 然后,将 Calendars.Read 作用域添加到 acquireTokenSilent 调用。Then add the Calendars.Read scope to the acquireTokenSilent call.

备注

增加作用域数量时,用户可能会收到接受其他许可的提示。Users might be prompted for additional consents as you increase the number of scopes.

已知问题Known issues

问题 1Issue 1

在 Azure AD 联盟域上登录应用程序时,可能会收到以下错误消息之一:You receive one of the following error messages when you sign in on your application on a federated Azure AD domain:

  • “在请求中未找到有效的客户端证书。”"No valid client certificate found in the request."
  • “在用户的证书存储中未找到有效的证书。”"No valid certificates found in the user's certificate store."
  • “请重试选择不同的身份验证方法。”"Try again choosing a different authentication method."

原因: 未启用企业功能和证书功能。Cause: Enterprise and certificate capabilities aren't enabled.

解决方案: 按照在联盟域中启用集成身份验证(可选)中的步骤操作。Solution: Follow the steps in Enable integrated authentication on federated domains (optional).

问题 2Issue 2

在联合域中启用集成身份验证,并尝试在 Windows 10 计算机上使用 Windows Hello 登录到配置了多重身份验证的环境。You enable integrated authentication on federated domains and try to use Windows Hello on a Windows 10 computer to sign in to an environment with multifactor authentication configured. 此时将显示证书列表。The list of certificates appears. 如果选择使用 PIN,则不会显示 PIN 窗口。If you choose to use your PIN, the PIN window never appears.

原因: 此问题是在 Windows 10 桌面版上运行的 UWP 应用程序中 Web 身份验证代理的已知限制。Cause: This issue is a known limitation of the web authentication broker in UWP applications that run on Windows 10 desktops. 该代理在 Windows 10 手机版上可正常工作。It works fine on Windows 10 Mobile.

解决方法: 选择“使用其他选项登录”。Workaround: Select Sign in with other options. 然后选择“使用用户名和密码登录”。Then select Sign in with a username and password. 选择“提供密码”。Select Provide your password. 然后完成手机身份验证过程。Then go through the phone authentication process.

帮助和支持Help and support

如果需要帮助、需要报告问题,或者需要详细了解支持选项,请参阅面向开发人员的帮助和支持If you need help, want to report an issue, or would like to learn about your support options, see Help and support for developers.