教程:从 Angular 单页应用程序将用户登录并调用 Microsoft Graph APITutorial: Sign in users and call the Microsoft Graph API from an Angular single-page application
在本教程中,你将构建一个 Angular 单页应用程序 (SPA),它使用户登录并调用 Microsoft Graph API。In this tutorial, you build an Angular single-page application (SPA) that signs in users and calls the Microsoft Graph API.
本教程的内容:In this tutorial:
- 使用
npm
创建 Angular 项目Create an Angular project withnpm
- 在 Azure 门户中注册应用程序Register the application in the Azure portal
- 添加代码以支持用户登录和注销Add code to support user sign-in and sign-out
- 添加代码以调用 Microsoft Graph APIAdd code to call Microsoft Graph API
- 测试应用程序Test the app
先决条件Prerequisites
- 用于运行本地 Web 服务器的 Node.js。Node.js for running a local web server.
- 用于修改项目文件的 Visual Studio Code 或其他编辑器。Visual Studio Code or other editor for modifying project files.
示例应用工作原理How the sample app works
本教程中创建的示例应用程序使 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 issued by the Microsoft identity platform. 它使用适用于 Angular 的 Microsoft 身份验证库 (MSAL),这是核心 MSAL.js 库的包装器。It uses the Microsoft Authentication Library (MSAL) for Angular, a wrapper of the core MSAL.js library. MSAL Angular 可以让 Angular 6+ 应用程序使用 Azure Active Directory (Azure AD) 对企业用户进行身份验证。MSAL Angular enables Angular 6+ applications to authenticate enterprise users by using Azure Active Directory (Azure AD). 使用此库,应用程序还可以获取对 Azure 云服务和 Microsoft Graph 的访问权限。The library also enables applications to get access to Azure cloud services and 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.
创建项目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
在 src/app 文件夹中,编辑 app.module.ts,将
MSALModule
添加到imports
并添加isIE
常量: In the src/app folder, edit app.module.ts and addMSALModule
toimports
as well as theisIE
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.cn 。For 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). 如果应用程序支持“任何组织目录中的帐户”,请将此值替换为 organizations。If your application supports accounts in any organizational directory, replace this value with organizations. Enter_the_Redirect_Uri_HereEnter_the_Redirect_Uri_Here 替换为 http://localhost:4200 。Replace with http://localhost:4200. 有关可用的可配置选项的详细信息,请阅读初始化客户端应用程序。For more information about available configurable options, see Initialize client applications.
在同一文件的顶部,添加以下 import 语句:At the top of the same file, add the following import statement:
import { MsalModule, MsalInterceptor } from '@azure/msal-angular';
将以下 import 语句添加到
src/app/app.component.ts
的顶部:Add the following import statements to the top ofsrc/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 用户,建议使用 loginRedirect
。We 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
. 在 protectedResourceMap
集合中输入的 URL 区分大小写。The URLs you provide in the protectedResourceMap
collection are case-sensitive.
@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 使用三个方法来获取令牌:acquireTokenRedirect
、acquireTokenPopup
和 acquireTokenSilent
。MSAL 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. 首次执行 loginRedirect
或 loginPopup
方法后,通常使用 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 使用 loginRedirect
和 acquireTokenRedirect
方法,因为 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
通过在命令行提示符下从应用程序文件夹运行以下命令,启动 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
在浏览器中输入 http://localhost:4200 或 http://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.
许可应用程序访问Provide consent for application access
首次开始登录到应用程序时,系统会提示你授予其访问你的个人资料的权限,并允许其将你登录: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 want to learn about your support options, see Help and support for developers.
后续步骤Next steps
在由多部分组成的文章系列中,深入了解 Microsoft 标识平台上的单页应用程序 (SPA) 开发。Delve deeper into single-page application (SPA) development on the Microsoft identity platform in our the multi-part article series.