教程:从 Angular 单页应用程序将用户登录并调用 Microsoft Graph APITutorial: Sign in users and call the Microsoft Graph API from an Angular single-page application

本教程演示了 Angular 单页应用程序 (SPA) 如何执行以下操作:This tutorial demonstrates how an Angular single-page application (SPA) can:

  • 登录工作帐户或学校帐户。Sign in work accounts, or school accounts.
  • 获取访问令牌。Acquire an access token.
  • 从 Microsoft 标识平台终结点调用需要访问令牌的 Microsoft Graph API 或其他 API。Call the Microsoft Graph API or other APIs that require access tokens from the Microsoft identity platform endpoint.

备注

本教程引导你使用 Microsoft 身份验证库 (MSAL) 创建新的 Angular SPA。This tutorial walks you through how to create a new Angular SPA by using Microsoft Authentication Library (MSAL). 若要下载示例应用,请参阅快速入门If you want to download a sample app, see the quickstart.

示例应用工作原理How the sample app works

示意图,展示了本教程中生成的示例应用的工作原理

详细信息More information

本教程中创建的示例应用程序是一个 Angular SPA,它能够查询 Microsoft Graph API 或 Web API,而该 API 接受来自 Microsoft 标识平台终结点的令牌。The sample application created in this tutorial enables an Angular SPA to query the Microsoft Graph API or a web API that accepts tokens from the Microsoft identity platform endpoint. 适用于 Angular 的 MSAL 库是核心 MSAL.js 库的包装器。The MSAL for Angular library is a wrapper of the core MSAL.js library. 它可以让 Angular (6+) 应用程序使用 Azure Active Directory 和社交标识用户(例如 LinkedIn)对企业用户进行身份验证。It enables Angular (6+) applications to authenticate enterprise users by using Azure Active Directory and social identity users (such as LinkedIn). 使用此库,应用程序还可以获取对 Azure 云服务或 Microsoft Graph 的访问权限。The library also enables the applications to get access to Azure cloud services or Microsoft Graph.

在此方案中,用户登录后请求了访问令牌,并通过授权标头将其添加到 HTTP 请求。In this scenario, after a user signs in, an access token is requested and added to HTTP requests through the authorization header. 令牌获取和续订通过 MSAL 处理。Token acquisition and renewal are handled by MSAL.

Libraries

本教程使用以下库:This tutorial uses the following library:

Library 说明Description
msal.jsmsal.js 适用于 JavaScript Angular 的 Microsoft 身份验证库包装器Microsoft Authentication Library for JavaScript Angular Wrapper

可以在 GitHub 上的 AzureAD/microsoft-authentication-library-for-js 存储库中找到 MSAL.js 库的源代码。You can find the source code for the MSAL.js library in the AzureAD/microsoft-authentication-library-for-js repository on GitHub.

先决条件Prerequisites

若要运行本教程,需要:To run this tutorial, you need:

  • 本地 Web 服务器,例如 Node.jsA local web server, such as Node.js. 本教程中的说明基于 Node.js。Instructions in this tutorial are based on Node.js.
  • 集成开发环境 (IDE)(例如 Visual Studio Code),用于编辑项目文件。An integrated development environment (IDE), such as Visual Studio Code, to edit the project files.

创建项目Create your project

使用以下 npm 命令生成一个新的 Angular 应用程序:Generate a new Angular application by using the following npm commands:

npm install -g @angular/cli@8                    # Install the Angular CLI
ng new my-application --routing=true --style=css # Generate a new Angular app
cd my-application                                # Change to the app directory
npm install @angular/material@8 @angular/cdk@8   # Install the Angular Material component library (optional, for UI)
npm install msal @azure/msal-angular             # Install MSAL and MSAL Angular in your application
ng generate component page-name                  # To add a new page (such as a home or profile page)

注册应用程序Register your application

按照说明在 Azure 门户中注册单页应用程序Follow the instructions to register a single-page application in the Azure portal.

在注册的应用“概述”页上,记下“应用程序(客户端) ID”值供稍后使用。 On the app Overview page of your registration, note the Application (client) ID value for later use.

注册 http://localhost:4200/ 作为“重定向 URI”,并启用隐式授权设置。Register your Redirect URI value as http://localhost:4200/ and enable implicit grant settings.

配置应用程序Configure the application

  1. 在 src/app 文件夹中,编辑 app.module.ts,将 MSALModule 添加到 imports 并添加 isIE 常量: In the src/app folder, edit app.module.ts and add MSALModule to imports as well as the isIE constant:

    const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        MsalModule.forRoot({
          auth: {
            clientId: 'Enter_the_Application_Id_here', // This is your client ID
            authority: 'Enter_the_Cloud_Instance_Id_Here'/'Enter_the_Tenant_Info_Here', // This is your tenant ID
            redirectUri: 'Enter_the_Redirect_Uri_Here'// This is your redirect URI
          },
          cache: {
            cacheLocation: 'localStorage',
            storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
          },
        }, {
          popUp: !isIE,
          consentScopes: [
            'https://microsoftgraph.chinacloudapi.cn/user.read',
            'openid',
            'profile',
          ],
          unprotectedResources: [],
          protectedResourceMap: [
            ['https://microsoftgraph.chinacloudapi.cn/v1.0/me', ['https://microsoftgraph.chinacloudapi.cn/user.read']]
          ],
          extraQueryParameters: {}
        })
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    

    替换以下值:Replace these values:

    值名称Value name 关于About
    Enter_the_Application_Id_HereEnter_the_Application_Id_Here 在应用程序注册的“概览”页中,这是你的“应用程序(客户端) ID”值。 On the Overview page of your application registration, this is your Application (client) ID value.
    Enter_the_Cloud_Instance_Id_HereEnter_the_Cloud_Instance_Id_Here 这是 Azure 云的实例。This is the instance of the Azure cloud. 对于主要云或全球 Azure 云,请输入 https://login.partner.microsoftonline.cnFor the main or global Azure cloud, enter https://login.partner.microsoftonline.cn. 对于国家/地区云(例如中国云),请参阅国家/地区云For national clouds (for example, China), see National clouds.
    Enter_the_Tenant_Info_HereEnter_the_Tenant_Info_Here 设置为以下选项之一:如果应用程序支持此组织目录中的帐户,请将此值替换为目录(租户)ID 或租户名称(例如 contoso.microsoft.com)。Set to one of the following options: If your application supports accounts in this organizational directory, replace this value with the directory (tenant) ID or tenant name (for example, contoso.microsoft.com). 如果应用程序支持“任何组织目录中的帐户”,请将此值替换为 organizationsIf your application supports accounts in any organizational directory, replace this value with organizations. 如果应用程序支持“任何组织目录中的帐户”,请将此值替换为“common”If your application supports accounts in any organizational directory, replace this value with common.
    Enter_the_Redirect_Uri_HereEnter_the_Redirect_Uri_Here 替换为 http://localhost:4200Replace with http://localhost:4200.

    有关可用的可配置选项的详细信息,请阅读初始化客户端应用程序For more information about available configurable options, see Initialize client applications.

  2. 在同一文件的顶部,添加以下 import 语句:At the top of the same file, add the following import statement:

    import { MsalModule, MsalInterceptor } from '@azure/msal-angular';
    
  3. 将以下 import 语句添加到 src/app/app.component.ts 的顶部:Add the following import statements to the top of src/app/app.component.ts:

    import { MsalService, BroadcastService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    

将用户登录Sign in a user

将以下代码添加到 AppComponent,以将用户登录:Add the following code to AppComponent to sign in a user:

export class AppComponent implements OnInit {
    constructor(private broadcastService: BroadcastService, private authService: MsalService) { }

    ngOnInit() { }

    login() {
        const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;

        if (isIE) {
          this.authService.loginRedirect({
            extraScopesToConsent: ["https://microsoftgraph.chinacloudapi.cn/user.read", "openid", "profile"]
          });
        } else {
          this.authService.loginPopup({
            extraScopesToConsent: ["https://microsoftgraph.chinacloudapi.cn/user.read", "openid", "profile"]
          });
        }
    }
}

提示

对于 Internet Explorer 用户,建议使用 loginRedirectWe recommend using loginRedirect for Internet Explorer users.

获取令牌Acquire a token

Angular 侦听器Angular Interceptor

MSAL Angular 向已知的受保护资源提供一个 Interceptor 类,该类可自动为使用 Angular http 客户端的传出请求获取令牌。MSAL Angular provides an Interceptor class that automatically acquires tokens for outgoing requests that use the Angular http client to known protected resources.

首先,将 Interceptor 类作为提供程序包含在应用程序中:First, include the Interceptor class as a provider to your application:

import { MsalInterceptor, MsalModule } from "@azure/msal-angular";
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";

@NgModule({
    // ...
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: MsalInterceptor,
            multi: true
        }
    ]
}

接下来,以 protectedResourceMap 形式提供受保护资源到 MsalModule.forRoot() 的映射,并将这些作用域包含在 consentScopes 中:Next, provide a map of protected resources to MsalModule.forRoot() as protectedResourceMap and include those scopes in consentScopes:

@NgModule({
  // ...
  imports: [
    // ...
    MsalModule.forRoot({
      auth: {
        clientId: 'Enter_the_Application_Id_here', // This is your client ID
        authority: 'https://login.partner.microsoftonline.cn/Enter_the_Tenant_Info_Here', // This is your tenant info
        redirectUri: 'Enter_the_Redirect_Uri_Here' // This is your redirect URI
      },
      cache: {
        cacheLocation: 'localStorage',
        storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
      },
    },
    {
      popUp: !isIE,
      consentScopes: [
        'https://microsoftgraph.chinacloudapi.cn/user.read',
        'openid',
        'profile',
      ],
      unprotectedResources: [],
      protectedResourceMap: [
        ['https://microsoftgraph.chinacloudapi.cn/v1.0/me', ['https://microsoftgraph.chinacloudapi.cn/user.read']]
      ],
      extraQueryParameters: {}
    })
  ],
});

最后,使用 HTTP 请求检索用户的配置文件:Finally, retrieve a user's profile with an HTTP request:

const graphMeEndpoint = "https://microsoftgraph.chinacloudapi.cn/v1.0/me";

getProfile() {
  this.http.get(graphMeEndpoint).toPromise()
    .then(profile => {
      this.profile = profile;
    });
}

acquireTokenSilent、acquireTokenPopup、acquireTokenRedirectacquireTokenSilent, acquireTokenPopup, acquireTokenRedirect

MSAL 使用三个方法来获取令牌:acquireTokenRedirectacquireTokenPopupacquireTokenSilentMSAL uses three methods to acquire tokens: acquireTokenRedirect, acquireTokenPopup, and acquireTokenSilent. 但是,对于 Angular 应用,我们建议改用 MsalInterceptor 类,如前一部分中所示。However, we recommend using the MsalInterceptor class instead for Angular apps, as shown in the previous section.

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

acquireTokenSilent 方法处理令牌获取和续订,且无需用户交互。The acquireTokenSilent method handles token acquisitions and renewal without user interaction. 首次执行 loginRedirectloginPopup 方法后,通常使用 acquireTokenSilent 获取用于在后续调用中访问受保护资源的令牌。After the loginRedirect or loginPopup method is executed for the first time, acquireTokenSilent is commonly used to obtain tokens used to access protected resources in later calls. 进行请求或续订令牌的调用时,以静默方式进行。Calls to request or renew tokens are made silently.

const requestObj = {
    scopes: ["https://microsoftgraph.chinacloudapi.cn/user.read"]
};

this.authService.acquireTokenSilent(requestObj).then(function (tokenResponse) {
    // Callback code here
    console.log(tokenResponse.accessToken);
}).catch(function (error) {
    console.log(error);
});

在该代码中,scopes 包含所请求的需要在 API 的访问令牌中返回的作用域。In that code, scopes contains scopes being requested to be returned in the access token for the API.

例如:For example:

  • Microsoft Graph 的 ["https://microsoftgraph.chinacloudapi.cn/user.read"]["https://microsoftgraph.chinacloudapi.cn/user.read"] for Microsoft Graph
  • 自定义 Web API 的 ["<Application ID URL>/scope"](即 api://<Application ID>/access_as_user["<Application ID URL>/scope"] for custom web APIs (that is, api://<Application ID>/access_as_user)

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

有时需要让用户与 Microsoft 标识平台终结点进行交互。Sometimes you need the user to interact with the Microsoft identity platform endpoint. 例如:For example:

  • 由于密码已过期,用户可能需要重新输入凭据。Users might need to reenter their credentials because their password has expired.
  • 应用程序正在请求访问用户需要许可的其他资源范围。Your application is requesting access to additional resource scopes that the user needs to consent to.
  • 需要双重身份验证。Two-factor authentication is required.

对于大多数应用程序,建议的模式是先调用 acquireTokenSilent,然后捕获异常,然后再调用 acquireTokenPopup(或 acquireTokenRedirect),以启动交互式请求。The recommended pattern for most applications is to call acquireTokenSilent first, then catch the exception, and then call acquireTokenPopup (or acquireTokenRedirect) to start an interactive request.

调用 acquireTokenPopup 会弹出一个登录窗口。Calling acquireTokenPopup results in a pop-up sign-in window. 另外,acquireTokenRedirect 会将用户重定向到 Microsoft 标识平台终结点。Alternatively, acquireTokenRedirect redirects users to the Microsoft identity platform endpoint. 在该窗口中,用户需要确认其凭据,许可访问所需的资源,或完成双重身份验证。In that window, users need to confirm their credentials, give consent to the required resource, or complete two-factor authentication.

  const requestObj = {
      scopes: ["https://microsoftgraph.chinacloudapi.cn/user.read"]
  };

  this.authService.acquireTokenPopup(requestObj).then(function (tokenResponse) {
      // Callback code here
      console.log(tokenResponse.accessToken);
  }).catch(function (error) {
      console.log(error);
  });

备注

本快速入门对 Microsoft Internet Explorer 使用 loginRedirectacquireTokenRedirect 方法,因为 Internet Explorer 浏览器处理弹出窗口时会出现一个已知问题This quickstart uses the loginRedirect and acquireTokenRedirect methods with Microsoft Internet Explorer because of a known issue related to the handling of pop-up windows by Internet Explorer.

注销Log out

添加以下代码来注销用户:Add the following code to log out a user:

logout() {
  this.authService.logout();
}

添加 UIAdd UI

有关如何使用 Angular Material 组件库添加 UI 的示例,请查看示例应用程序For an example of how to add UI by using the Angular Material component library, see the sample application.

测试代码Test your code

  1. 通过在命令行提示符下从应用程序文件夹运行以下命令,启动 Web 服务器来侦听端口:Start the web server to listen to the port by running the following commands at a command-line prompt from the application folder:

    npm install
    npm start
    
  2. 在浏览器中输入 http://localhost:4200http://localhost:{port} ,其中,port 是 Web 服务器正在侦听的端口。In your browser, enter http://localhost:4200 or http://localhost:{port}, where port is the port that your web server is listening on.

首次开始登录到应用程序时,系统会提示你授予其访问你的个人资料的权限,并允许其将你登录:The first time that you start to sign in to your application, you're prompted to grant it access to your profile and allow it to sign you in:

“请求的权限”窗口

添加范围和委托的权限Add scopes and delegated permissions

Microsoft Graph API 需要 user.read 作用域来读取用户的个人资料。The Microsoft Graph API requires the user.read scope to read a user's profile. 默认情况下,在注册门户上注册的每个应用程序中,都会自动添加此范围。By default, this scope is automatically added in every application that's registered on the registration portal. Microsoft Graph 的其他 API 以及后端服务器的自定义 API 可能需要其他作用域。Other APIs for Microsoft Graph, as well as custom APIs for your back-end server, might require additional scopes. 例如,Microsoft Graph API 需要使用 Calendars.Read 作用域才能列出用户的日历。For example, the Microsoft Graph API requires the Calendars.Read scope in order 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.

备注

当你增加作用域数量时,可能会提示用户另外进行许可。The user might be prompted for additional consents as you increase the number of scopes.

如果后端 API 不需要范围(不建议),则你可以将 clientId 用作调用中的范围来获取令牌。If a back-end API doesn't require a scope (not recommended), you can use clientId as the scope in the calls to acquire tokens.

帮助和支持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.

后续步骤Next steps

如果不熟悉标识和访问管理,可以参阅我们提供的几篇文章(从身份验证与授权开始),以便学习新式身份验证概念。If you're new to identity and access management, we have several articles to help you learn modern authentication concepts, starting with authentication vs. authorization.

若要更深入地了解 Microsoft 标识平台上的单页应用程序开发,可以参阅由多部分组成的方案:单页应用程序系列文章,了解如何入门。If you'd like to dive deeper into single-page application development on the Microsoft identity platform, the multi-part Scenario: Single-page application series of articles can help you get started.