快速入门:从 .NET 桌面 (WPF) 应用将用户登录并调用 Microsoft Graph APIQuickstart: Sign in users and call the Microsoft Graph API from a .NET Desktop (WPF) app

适用于:Applies to:
  • Azure AD v1.0 终结点Azure AD v1.0 endpoint
  • Azure Active Directory Authentication Library (ADAL)Azure Active Directory Authentication Library (ADAL)

对于需要访问受保护资源的 .NET 本机客户端,Azure Active Directory (Azure AD) 提供了 Active Directory 身份验证库 (ADAL)。For .NET native clients that need to access protected resources, Azure Active Directory (Azure AD) provides the Active Directory Authentication Library (ADAL). 使用 ADAL,应用可以轻松获取访问令牌。ADAL makes it easy for your app to get access tokens.

在本快速入门中,你将学习如何生成具有以下功能的 .NET WPF 待办事项列表应用程序:In this quickstart, you'll learn how to build a .NET WPF To-Do List application that:

  • 使用 OAuth 2.0 身份验证协议获取用于调用 Azure AD Graph API 的访问令牌。Gets access tokens for calling the Azure AD Graph API using the OAuth 2.0 authentication protocol.
  • 在目录中搜索具有给定别名的用户。Searches a directory for users with a given alias.
  • 将用户注销。Signs users out.

要构建完整的工作应用程序,需要:To build the complete, working application, you'll need to:

  1. 将应用程序注册到 Azure AD。Register your application with Azure AD.
  2. 安装并配置 ADAL。Install and configure ADAL.
  3. 使用 ADAL 从 Azure AD 获取令牌。Use ADAL to get tokens from Azure AD.

先决条件Prerequisites

开始前,请完成这些先决条件:To get started, complete these prerequisites:

步骤 1:注册 DirectorySearcher 应用程序Step 1: Register the DirectorySearcher application

为了使应用能够获取令牌,请在 Azure AD 租户中注册该应用,并授予它访问 Azure AD Graph API 的权限:To enable your app to get tokens, register your app in your Azure AD tenant and grant it permission to access the Azure AD Graph API:

  1. 登录到 Azure 门户Sign in to the Azure portal.

  2. 在顶栏上选择你的帐户,并在“目录”列表下选择要注册应用程序的 Active Directory 租户。On the top bar, select your account and under the Directory list, choose the Active Directory tenant where you wish to register your application.

  3. 选择左侧导航栏中的“所有服务”,并选择“Azure Active Directory”。Select on All services in the left-hand nav, and choose Azure Active Directory.

  4. 在“应用注册”上,选择“添加”。On App registrations, choose Add.

  5. 根据提示创建一个新的“本机”客户端应用程序。Follow the prompts and create a new Native client application.

    • 应用程序的“名称”将向最终用户描述应用程序The Name of the application will describe your application to end users
    • “重定向 URI” 是 Azure AD 要用来返回令牌响应的方案与字符串组合。The Redirect Uri is a scheme and string combination that Azure AD will use to return token responses. 输入特定于你的应用程序的值,例如 http://DirectorySearcherEnter a value specific to your application, for example, http://DirectorySearcher.
  6. 完成注册后,AAD 将为应用分配唯一的应用程序 ID。Once you've completed registration, AAD will assign your app a unique Application ID. 在后面的部分中会用到此值,因此,请从应用程序页复制此值。You'll need this value in the next sections, so copy it from the application page.

  7. 在“设置”页上,依次选择“所需权限”和“添加”。From the Settings page, choose Required permissions and choose Add. 选择“Microsoft Graph”作为 API,并在“委派的权限”下添加“读取目录数据”权限。Select Microsoft Graph as the API, and under Delegated permissions add the Read directory data permission. 设置此权限后,应用程序便可以在图形 API 中查询用户。Setting this permission enables your application to query the Graph API for users.

步骤 2:安装并配置 ADALStep 2: Install and configure ADAL

将应用程序注册到 Azure AD 后,可以安装 ADAL 并编写标识相关的代码。Now that you have an application in Azure AD, you can install ADAL and write your identity-related code. 为了使 ADAL 能够与 Azure AD 进行通信,需要为 ADAL 提供一些有关应用注册的信息。For ADAL to communicate with Azure AD, you need to provide it with some information about your app registration.

  1. 首先,使用程序包管理器控制台将 ADAL 添加到 DirectorySearcher 项目。Begin by adding ADAL to the DirectorySearcher project using the Package Manager Console.

    PM> Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
    
  2. DirectorySearcher 项目中,打开 app.configIn the DirectorySearcher project, open app.config.

  3. 替换 <appSettings> 节中的元素值,以反映你在 Azure 门户中输入的值。Replace the values of the elements in the <appSettings> section to reflect the values you input into the Azure portal. 只要使用 ADAL,代码就会引用这些值。Your code will reference these values whenever it uses ADAL.

    • ida:Tenant 是 Azure AD 租户的域,例如,contoso.partner.onmschina.cnThe ida:Tenant is the domain of your Azure AD tenant, for example, contoso.partner.onmschina.cn
    • ida:ClientId 是你从门户中复制的应用程序的客户端 ID。The ida:ClientId is the client ID of your application you copied from the portal.
    • ida:RedirectUri 是你在门户中注册的 URL。The ida:RedirectUri is the redirect URL you registered in the portal.

步骤 3:使用 ADAL 从 Azure AD 获取令牌Step 3: Use ADAL to get tokens from Azure AD

ADAL 遵守的基本原理是,每当应用需要访问令牌时,它只需调用 authContext.AcquireTokenAsync(...),ADAL 会负责其余的工作。The basic principle behind ADAL is that whenever your app needs an access token, your app simply calls authContext.AcquireTokenAsync(...), and ADAL does the rest.

  1. DirectorySearcher 项目中,打开 MainWindow.xaml.csIn the DirectorySearcher project, open MainWindow.xaml.cs.

  2. 找到 MainWindow() 方法。Locate the MainWindow() method.

  3. 初始化你的应用的 AuthenticationContext - ADAL 的主类。Initialize your app's AuthenticationContext - ADAL's primary class. AuthenticationContext 用于传递 ADAL 与 Azure AD 通信时所需的坐标,并告诉 ADAL 如何缓存令牌。is where you pass ADAL the coordinates it needs to communicate with Azure AD and tell it how to cache tokens.

    public MainWindow()
    {
        InitializeComponent();
    
        authContext = new AuthenticationContext(authority, new FileCache());
    
        CheckForCachedToken();
    }
    
  4. 找到 Search(...) 方法,当用户在应用的 UI 中单击“搜索”按钮时,将调用该方法。Locate the Search(...) method, which will be called when the user selects the Search button in the app's UI. 此方法向 Azure AD 图形 API 发出 GET 请求,以查询其 UPN 以给定搜索词开头的用户。This method makes a GET request to the Azure AD Graph API to query for users whose UPN begins with the given search term.

  5. 若要查询图形 API,请在请求的 Authorization 标头中包含 access_token - 这是 ADAL 的进入位置。To query the Graph API, include an access_token in the Authorization header of the request, which is where ADAL comes in.

    private async void Search(object sender, RoutedEventArgs e)
    {
        // Validate the Input String
        if (string.IsNullOrEmpty(SearchText.Text))
        {
            MessageBox.Show("Please enter a value for the To Do item name");
            return;
        }
    
        // Get an Access Token for the Graph API
        AuthenticationResult result = null;
        try
        {
            result = await authContext.AcquireTokenAsync(graphResourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Auto));
            UserNameLabel.Content = result.UserInfo.DisplayableId;
            SignOutButton.Visibility = Visibility.Visible;
        }
        catch (AdalException ex)
        {
            // An unexpected error occurred, or user canceled the sign in.
            if (ex.ErrorCode != "access_denied")
                MessageBox.Show(ex.Message);
    
            return;
        }
    
        ...
    }
    

    当应用程序通过调用 AcquireTokenAsync(...)请求令牌时,ADAL 将尝试返回一个令牌,而不要求用户输入凭据。When your app requests a token by calling AcquireTokenAsync(...), ADAL will attempt to return a token without asking the user for credentials.

    • 如果 ADAL 确定用户需要登录以获取令牌,就会显示登录对话框,收集用户的凭据,并在身份验证成功后返回令牌。If ADAL determines that the user needs to sign in to get a token, it will display a login dialog, collect the user's credentials, and return a token upon successful authentication.
    • 如果 ADAL 出于任何原因无法返回令牌,则会引发 AdalExceptionIf ADAL is unable to return a token for any reason, it will throw an AdalException.
  6. 请注意,AuthenticationResult 对象包含 UserInfo 对象,后者可用于收集应用程序可能需要的信息。Notice that the AuthenticationResult object contains a UserInfo object that can be used to collect information your app may need. 在 DirectorySearcher 中,UserInfo 用于使用用户 ID 自定义应用的 UI。In the DirectorySearcher, UserInfo is used to customize the app's UI with the user's ID.

  7. 当用户选择“注销”按钮时,请确保 AcquireTokenAsync(...) 的后续调用将要求用户登录。When the user selects the Sign out button, make sure that the next call to AcquireTokenAsync(...) will ask the user to sign in. 你可以通过清除令牌缓存轻松使用 ADAL 执行此操作:You can easily do this with ADAL by clearing the token cache:

    private void SignOut(object sender = null, RoutedEventArgs args = null)
    {
        // Clear the token cache
        authContext.TokenCache.Clear();
    
        ...
    }
    

    如果用户未单击“注销”按钮,则需要保留用户的会话,以在他们下次运行 DirectorySearcher 时使用。If the user does not click the Sign out button, you need to maintain the user's session for the next time they run the DirectorySearcher. 当应用启动时,可以检查现有令牌的 ADAL 令牌缓存,并相应地更新 UI。When the app launches, you can check ADAL's token cache for an existing token and update the UI accordingly.

  8. CheckForCachedToken() 方法中,再次调用 AcquireTokenAsync(...),此次传入 PromptBehavior.Never 参数。In the CheckForCachedToken() method, make another call to AcquireTokenAsync(...), this time passing in the PromptBehavior.Never parameter. PromptBehavior.Never 将告知 ADAL 不应提示用户登录;如果 ADAL 无法返回令牌,则应引发异常。will tell ADAL that the user should not be prompted for sign in, and ADAL should instead throw an exception if it is unable to return a token.

    public async void CheckForCachedToken() 
    {
        // As the application starts, try to get an access token without prompting the user. If one exists, show the user as signed in.
        AuthenticationResult result = null;
        try
        {
            result = await authContext.AcquireTokenAsync(graphResourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Never));
        }
        catch (AdalException ex)
        {
            if (ex.ErrorCode != "user_interaction_required")
            {
                // An unexpected error occurred.
                MessageBox.Show(ex.Message);
            }
    
            // If user interaction is required, proceed to main page without signing the user in.
            return;
        }
    
        // A valid token is in the cache
        SignOutButton.Visibility = Visibility.Visible;
        UserNameLabel.Content = result.UserInfo.DisplayableId;
    }
    

祝贺!Congratulations! 现在,你已有了一个可正常工作的 .NET WPF 应用程序,它可以对用户进行身份验证,使用 OAuth 2.0 安全地调用 Web API,并获取有关用户的基本信息。You now have a working .NET WPF application that can authenticate users, securely call Web APIs using OAuth 2.0, and get basic information about the user. 如果尚未这样做,可以在租户中填充一些用户。If you haven't already, now is the time to populate your tenant with some users. 运行 DirectorySearcher 应用,并使用这些用户之一进行登录。Run your DirectorySearcher app, and sign in with one of those users. 根据用户的 UPN 搜索其他用户。Search for other users based on their UPN. 关闭应用,并重新运行应用。Close the app, and rerun it. 请注意,用户的会话将保持不变。Notice how the user's session stays intact. 注销,并以其他用户身份重新登录。Sign out, and sign back in as another user.

使用 ADAL 可以方便地将这些常见标识功能整合到应用程序中。ADAL makes it easy to incorporate these common identity features into your application. 它会负责所有的繁琐工作 - 包括缓存管理、OAuth 协议支持、向户显示登录名 UI、刷新已过期的令牌,等等。It takes care of the dirty work for you, including cache management, OAuth protocol support, presenting the user with a login UI, refreshing expired tokens, and more. 只需要真正了解一个 API 调用,即 authContext.AcquireTokenAsync(...)All you really need to know is a single API call, authContext.AcquireTokenAsync(...).

有关参考,请参阅 GitHub 上的已完成示例(不含你的配置值)。For reference, see the completed sample (without your configuration values) on GitHub.

后续步骤Next steps

了解如何使用 OAuth 2.0 持有者访问令牌保护 Web API。Learn how to protect a web API by using OAuth 2.0 bearer access tokens.