Tutorial:在 Node.js 控制台应用中调用 Microsoft Graph APITutorial: Call the Microsoft Graph API in a Node.js console app

在本教程中,你将构建一个控制台应用,该应用使用其自己的身份调用 Microsoft Graph API。In this tutorial, you build a console app that calls Microsoft Graph API using its own identity. 构建的控制台应用使用适用于 Node.js 的 Microsoft 身份验证库 (MSAL)The console app you build uses the Microsoft Authentication Library (MSAL) for Node.js.

请按照本教程中的步骤进行操作:Follow the steps in this tutorial to:

  • 在 Azure 门户中注册应用程序Register the application in the Azure portal
  • 创建 Node.js 控制台应用项目Create a Node.js console app project
  • 向应用添加身份验证逻辑Add authentication logic to your app
  • 添加应用注册详细信息Add app registration details
  • 添加方法来调用 web APIAdd a method to call a web API
  • 测试应用程序Test the app

先决条件Prerequisites

注册应用程序Register the application

首先,请完成向 Microsoft 标识平台注册应用程序中的步骤来注册你的应用。First, complete the steps in Register an application with the Microsoft identity platform to register your app.

对于应用注册,请使用以下设置:Use the following settings for your app registration:

  • 名称:NodeConsoleApp(建议)Name: NodeConsoleApp (suggested)
  • 支持的帐户类型:仅此组织目录中的帐户Supported account types: Accounts in this organizational directory only
  • API 权限:Microsoft API > Microsoft Graph > 应用程序权限 > User.Read.AllAPI permissions: Microsoft APIs > Microsoft Graph > Application Permissions > User.Read.All
  • 客户端机密:*********(记录此值以便在后面的步骤中使用 - 它只显示一次)Client secret: ********* (record this value for use in a later step - it's shown only once)

创建项目Create the project

创建文件夹来承载你的应用程序,例如 NodeConsoleApp。Create a folder to host your application, for example NodeConsoleApp.

  1. 首先,在终端中更改到你的项目目录,然后运行以下NPM 命令:First, change to your project directory in your terminal and then run the following NPM commands:
    npm init -y
    npm install --save dotenv yargs axios @azure/msal-node
  1. 接下来,创建一个名为 bin 的文件夹。Next, create a folder named bin. 然后,在此文件夹中创建名为 index.js 的文件,并添加以下代码:Then, inside this folder, create file named index.js and add the following code:
#!/usr/bin/env node

// read in env settings
require('dotenv').config();

const yargs = require('yargs');

const fetch = require('./fetch');
const auth = require('./auth');

const options = yargs
    .usage('Usage: --op <operation_name>')
    .option('op', { alias: 'operation', describe: 'operation name', type: 'string', demandOption: true })
    .argv;

async function main() {
    console.log(`You have selected: ${options.op}`);

    switch (yargs.argv['op']) {
        case 'getUsers':

            try {
                // here we get an access token
                const authResponse = await auth.getToken(auth.tokenRequest);

                // call the web API with the access token
                const users = await fetch.callApi(auth.apiConfig.uri, authResponse.accessToken);

                // display result
                console.log(users);
            } catch (error) {
                console.log(error);
            }

            break;
        default:
            console.log('Select a Graph operation first');
            break;
    }
};

main();

此文件引用两个其他节点模块:auth.js 和 fetch.js,前者包含用于获取访问令牌的 MSAL 节点的实现,后者包含用于发出 HTTP 请求以使用访问令牌 Microsoft Graph API 的方法 。This file references two other node modules: auth.js which contains an implementation of MSAL Node for acquiring access tokens, and fetch.js which contains a method for making an HTTP request to Microsoft Graph API with an access token. 完成本教程的其余部分之后,项目的文件和文件夹结构应类似于下面这样:After completing the rest of the tutorial, the file and folder structure of your project should look similar to the following:

NodeConsoleApp/
├── bin
│   ├── auth.js
│   ├── fetch.js
│   ├── index.js
├── package.json
└── .env

添加身份验证逻辑Add authentication logic

在 bin 文件夹中,创建另一个名为 auth.js 的文件,并添加以下代码,以便获取调用 Microsoft Graph API 时要提供的访问令牌 。Inside the bin folder, create another file named auth.js and add the following code for acquiring an access token to present when calling the Microsoft Graph API.

const msal = require('@azure/msal-node');

/**
 * Configuration object to be passed to MSAL instance on creation.
 * For a full list of MSAL Node configuration parameters, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
 */
const msalConfig = {
    auth: {
        clientId: process.env.CLIENT_ID,
        authority: process.env.AAD_ENDPOINT + process.env.TENANT_ID,
        clientSecret: process.env.CLIENT_SECRET,
    }
};

/**
 * With client credentials flows permissions need to be granted in the portal by a tenant administrator.
 * The scope is always in the format '<resource>/.default'. For more, visit:
 * /active-directory/develop/v2-oauth2-client-creds-grant-flow
 */
const tokenRequest = {
    scopes: [process.env.GRAPH_ENDPOINT + '.default'],
};

const apiConfig = {
    uri: process.env.GRAPH_ENDPOINT + 'v1.0/users',
};

/**
 * Initialize a confidential client application. For more info, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/initialize-confidential-client-application.md
 */
const cca = new msal.ConfidentialClientApplication(msalConfig);

/**
 * Acquires token with client credentials.
 * @param {object} tokenRequest
 */
async function getToken(tokenRequest) {
    return await cca.acquireTokenByClientCredential(tokenRequest);
}

module.exports = {
    apiConfig: apiConfig,
    tokenRequest: tokenRequest,
    getToken: getToken
};

在上述代码片段中,我们首先创建一个 (msalConfig) 的配置对象,并将其传递给 MSAL ConfidentialClientApplicationIn the code snippet above, we first create a configuration object (msalConfig) and pass it to initialize an MSAL ConfidentialClientApplication. 接下来,我们创建一个方法,用于通过客户端凭据获取令牌,并最终公开此模块以便通过 main.js 进行访问。Then we create a method for acquiring tokens via client credentials and finally expose this module to be accessed by main.js. 此模块中的配置参数是从环境文件中提取的,我们将在下一步中创建该文件。The configuration parameters in this module are drawn from an environment file, which we will create in the next step.

添加应用注册详细信息Add app registration details

创建一个环境文件,以存储在获取令牌时将使用的应用注册详细信息。Create an environment file to store the app registration details that will be used when acquiring tokens. 为此,请在示例 (NodeConsoleApp) 的根文件夹中创建一个名为 .env 的文件,并添加以下代码 :To do so, create a file named .env inside the root folder of the sample (NodeConsoleApp), and add the following code:

# Credentials
TENANT_ID=Enter_the_Tenant_Id_Here
CLIENT_ID=Enter_the_Application_Id_Here
CLIENT_SECRET=Enter_the_Client_Secret_Here

# Endpoints
AAD_ENDPOINT=Enter_the_Cloud_Instance_Id_Here
GRAPH_ENDPOINT=Enter_the_Graph_Endpoint_Here

使用从 Azure 应用注册门户获取的值填写以下详细信息:Fill in these details with the values you obtain from Azure app registration portal:

  • Enter_the_Tenant_Id_here 应是以下各项之一:Enter_the_Tenant_Id_here should be one of the following:
    • 如果应用程序支持“此组织目录中的帐户”,请将此值替换为“租户 ID”或“租户名称”。If your application supports accounts in this organizational directory, replace this value with the Tenant ID or Tenant name. 例如,contoso.microsoft.comFor example, contoso.microsoft.com.
    • 如果应用程序支持“任何组织目录中的帐户”,请将该值替换为“organizations”。If your application supports accounts in any organizational directory, replace this value with organizations.
  • Enter_the_Application_Id_Here:已注册应用程序的应用程序(客户端)ID。Enter_the_Application_Id_Here: The Application (client) ID of the application you registered.
  • Enter_the_Cloud_Instance_Id_Here:在其中注册应用程序的 Azure 云实例。Enter_the_Cloud_Instance_Id_Here: The Azure cloud instance in which your application is registered.
    • 对于国家/地区云(例如中国云),可以在国家/地区云中找到相应值。For national clouds (for example, China), you can find appropriate values in National clouds.
  • Enter_the_Graph_Endpoint_Here 是应用程序应与之通信的 Microsoft Graph API 实例。Enter_the_Graph_Endpoint_Here is the instance of the Microsoft Graph API the application should communicate with.

添加方法来调用 Web APIAdd a method to call a web API

在 bin 文件夹中创建另一个名为 fetch.js 的文件,并添加以下代码以对 Microsoft Graph API 进行 REST 调用 :Inside the bin folder, create another file named fetch.js and add the following code for making REST calls to the Microsoft Graph API:

const axios = require('axios');

/**
 * Calls the endpoint with authorization bearer token.
 * @param {string} endpoint
 * @param {string} accessToken
 */
async function callApi(endpoint, accessToken) {

    const options = {
        headers: {
            Authorization: `Bearer ${accessToken}`
        }
    };

    console.log('request made to web API at: ' + new Date().toString());

    try {
        const response = await axios.default.get(endpoint, options);
        return response.data;
    } catch (error) {
        console.log(error)
        return error;
    }
};

module.exports = {
    callApi: callApi
};

此处,使用 callApi 方法对需要令牌的受保护资源发出 HTTP GET 请求。Here, the callApi method is used to make an HTTP GET request against a protected resource that requires an access token. 然后,该请求将内容返回给调用方。The request then returns the content to the caller. 此方法可在 HTTP 授权标头中添加获取的令牌。This method adds the acquired token in the HTTP Authorization header. 此处的受保护资源是 Microsoft Graph API 用户终结点,该终结点显示在其中注册了此应用的租户中的用户。The protected resource here is the Microsoft Graph API users endpoint which displays the users in the tenant where this app is registered.

测试应用Test the app

你已完成应用程序的创建,现在即可测试应用的功能。You've completed creation of the application and are now ready to test the app's functionality.

从项目文件夹的根目录中运行以下命令,启动 Node.js 控制台应用:Start the Node.js console app by running the following command from within the root of your project folder:

node . --op getUsers

这会导致某些来自 Microsoft Graph API 的 JSON 响应,你应在控制台中看到用户对象的数组:This should result in some JSON response from Microsoft Graph API and you should see an array of user objects in the console:

You have selected: getUsers
request made to web API at: Fri Jan 22 2021 09:31:52 GMT-0800 (Pacific Standard Time)
{
    '@odata.context': 'https://microsoftgraph.chinacloudapi.cn/v1.0/$metadata#users',
    value: [
        {
            displayName: 'Adele Vance'
            givenName: 'Adele',
            jobTitle: 'Retail Manager',
            mail: 'AdeleV@msaltestingjs.partner.onmschina.cn',
            mobilePhone: null,
            officeLocation: '18/2111',
            preferredLanguage: 'en-US',
            surname: 'Vance',
            userPrincipalName: 'AdeleV@msaltestingjs.partner.onmschina.cn',
            id: 'a6a218a5-f5ae-462a-acd3-581af4bcca00'
        }
    ]
}

显示 Graph 响应的命令行接口

应用程序的工作原理How the application works

此应用程序使用 OAuth 2.0 客户端凭据授权This application uses OAuth 2.0 client credentials grant. 这种授予通常用于必须在后台运行的服务器间交互,不需要立即与用户交互。This type of grant is commonly used for server-to-server interactions that must run in the background, without immediate interaction with a user. 凭据授权流允许 Web 服务(机密客户端)在调用其他 Web 服务时使用它自己的凭据(而不是模拟用户)进行身份验证。The credentials grant flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service. 此身份验证模型支持的应用程序类型通常是守护程序或服务帐户 。The type of applications supported with this authentication model are usually daemons or service accounts.

请求客户端凭据流时,其作用域是资源的名称后跟 /.defaultThe scope to request for a client credential flow is the name of the resource followed by /.default. 此表示法告知 Azure Active Directory (Azure AD) 使用在应用程序注册过程中静态声明的应用程序级权限。This notation tells Azure Active Directory (Azure AD) to use the application-level permissions declared statically during application registration. 另外,这些 API 权限必须由租户管理员授予。Also, these API permissions must be granted by a tenant administrator.

后续步骤Next steps

如果你想要更深入了解 Microsoft 标识平台上的 Node.js 控制台应用程序开发,请参阅由多部分组成的方案系列:If you'd like to dive deeper into Node.js console application development on the Microsoft identity platform, see our multi-part scenario series: