教程:在 Node.js 控制台守护程序应用中调用 Microsoft 图形 API

在本教程中,你将构建一个控制台守护程序应用,该应用使用其自己的身份调用 Microsoft 图形 API。 构建的守护程序应用使用适用于 Node.js 的 Microsoft 身份验证库 (MSAL)

请按照本教程中的步骤进行操作:

  • 在 Azure 门户中注册应用程序
  • 创建 Node.js 控制台守护程序应用项目
  • 向应用添加身份验证逻辑
  • 添加应用注册详细信息
  • 添加方法来调用 web API
  • 测试应用程序

先决条件

注册应用程序

首先,请完成向 Microsoft 标识平台注册应用程序中的步骤来注册你的应用。

对于应用注册,请使用以下设置:

  • 名称:NodeDaemonApp(建议)
  • 支持的帐户类型:仅此组织目录中的帐户
  • API 权限:Microsoft API>Microsoft Graph>应用程序权限>User.Read.All
  • 客户端机密:*********(记录此值以便在后面的步骤中使用 - 它只显示一次)

创建项目

  1. 首先为此 Node.js 教程项目创建一个目录。 例如 NodeDaemonApp。

  2. 在终端中,切换到你创建的目录(项目根目录),然后运行以下命令:

    npm init -y
    npm install --save dotenv yargs axios @azure/msal-node
    
  3. 接下来,编辑项目根目录中的 package.json 文件,并在 main 的值前面加上 bin/,如下所示:

    "main": "bin/index.js",
    
  4. 现在,创建 bin 目录,并在 bin 内,将以下代码添加到名为 index.js 的新文件中 :

    #!/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();
    

你刚刚创建的 index.js 文件引用了你接下来将创建的另外两个节点模块:

  • auth.js - 使用 MSAL 节点从 Microsoft 标识平台获取访问令牌。
  • fetch.js - 通过在对 API 的 HTTP 请求中包含访问令牌(在 auth.js 中获取)从 Microsoft Graph API 请求数据 。

在本教程结束时,项目的文件和目录结构应类似于:

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

添加身份验证逻辑

在 bin 目录中,将以下代码添加到名为 auth.js 的新文件中 。 auth.js 中的代码从 Microsoft 标识平台获取访问令牌,以包含在 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 ConfidentialClientApplication。 接下来,我们创建一个方法,用于通过客户端凭据获取令牌,并最终公开此模块以便通过 main.js 进行访问。 此模块中的配置参数是从环境文件中提取的,我们将在下一步中创建该文件。

添加应用注册详细信息

创建一个环境文件,以存储在获取令牌时将使用的应用注册详细信息。 为此,请在示例 (NodeDaemonApp) 的根文件夹中创建一个名为 .env 的文件,并添加以下代码:

# 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 应用注册门户获取的值填写以下详细信息:

  • Enter_the_Tenant_Id_here 应是以下各项之一:
    • 如果应用程序支持“此组织目录中的帐户”,请将此值替换为“租户 ID”或“租户名称”。 例如,contoso.microsoft.com
    • 如果应用程序支持“任何组织目录中的帐户”,请将该值替换为“organizations”。
  • Enter_the_Application_Id_Here:已注册应用程序的应用程序(客户端)ID。
  • Enter_the_Cloud_Instance_Id_Here:在其中注册应用程序的 Azure 云实例。
    • 对于国家/地区云(例如中国云),可以在国家/地区云中找到相应值。
  • Enter_the_Graph_Endpoint_Here 是应用程序应与之通信的 Microsoft Graph API 实例。
    • 对于国家/地区云部署中的终结点,请参阅 Microsoft Graph 文档中的国家/地区云部署

添加方法来调用 Web API

在 bin 文件夹中创建另一个名为 fetch.js 的文件,并添加以下代码以对 Microsoft Graph API 进行 REST 调用 :

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.get(endpoint, options);
        return response.data;
    } catch (error) {
        console.log(error)
        return error;
    }
};

module.exports = {
    callApi: callApi
};

此处,使用 callApi 方法对需要令牌的受保护资源发出 HTTP GET 请求。 然后,该请求将内容返回给调用方。 此方法可在 HTTP 授权标头中添加获取的令牌。 此处的受保护资源是 Microsoft Graph API 用户终结点,该终结点显示在其中注册了此应用的租户中的用户。

测试应用

你已完成应用程序的创建,现在即可测试应用的功能。

从项目文件夹的根目录中运行以下命令,启动 Node.js 控制台守护程序应用:

node . --op getUsers

这会导致某些来自 Microsoft Graph API 的 JSON 响应,你应在控制台中看到用户对象的数组:

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'
        }
    ]
}

Command-line interface displaying Graph response

应用程序的工作原理

此应用程序使用 OAuth 2.0 客户端凭据授权。 这种授予通常用于必须在后台运行的服务器间交互,不需要立即与用户交互。 凭据授权流允许 Web 服务(机密客户端)在调用其他 Web 服务时使用它自己的凭据(而不是模拟用户)进行身份验证。 此身份验证模型支持的应用程序类型通常是守护程序或服务帐户 。

请求客户端凭据流时,其作用域是资源的名称后跟 /.default。 这种表示法告知 Microsoft Entra ID 使用在应用程序注册过程中静态声明的应用程序级权限。 另外,这些 API 权限必须由租户管理员授予。

后续步骤

如果你想要更深入了解 Microsoft 标识平台上的 Node.js 守护程序应用程序开发,请参阅由多部分组成的方案系列: