分享方式:


教學課程:從 Node.js 精靈應用程式呼叫 Web API

本教學課程是系列的最後一部分,示範如何使用 Open Authorization (OAuth) 2.0 用戶端認證授與流程來準備 Node.js 精靈用戶端應用程式,然後將其設定為取得用於呼叫 Web API 的存取權杖。 在此系列的第 1 部分中,您已在 Microsoft Entra 系統管理中心內註冊 Web API 和精靈應用程式,並授與權限。 這個最後一個步驟示範如何使用適用於 Node 的 Microsoft 驗證程式庫 (MSAL) 來建置 Node.js 應用程式,以簡化將授權新增至您的應用程式。

本教學課程內容;

  • 在 Visual Studio Code 中建立 Node.js 應用程式,然後安裝相依性。
  • 讓 Node.js 應用程式取得用於呼叫 Web API 的存取權杖。

必要條件

建立 Node.js 精靈專案

建立資料夾以裝載您的 Node 精靈應用程式 (例如 ciam-call-api-node-daemon):

  1. 在終端機中,將目錄變更為您的 Node 精靈應用程式資料夾 (例如 cd ciam-call-api-node-daemon),然後執行 npm init -y。 此命令會為 Node.js 專案建立預設 package.json 檔案。 此命令會建立 Node.js 專案的預設 package.json 檔案。

  2. 建立其他資料夾和檔案,以達成下列專案結構:

        ciam-call-api-node-daemon/
        ├── auth.js
        └── authConfig.js
        └── fetch.js
        └── index.js 
        └── package.json
    

安裝應用程式相依性

在終端機中,執行下列命令以安裝 axiosyargs@azure/msal-node 套件:

npm install axios yargs @azure/msal-node   

建立 MSAL 設定物件

在您的程式碼編輯器中,開啟 authConfig.js 檔案,然後新增下列程式碼:

require('dotenv').config();

/**
 * 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 || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
        authority: process.env.AUTHORITY || 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace "Enter_the_Tenant_Subdomain_Here" with your tenant subdomain
        clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app 
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: 'Info',
        },
    },
};    
const protectedResources = {
    apiToDoList: {
        endpoint: process.env.API_ENDPOINT || 'https://localhost:44351/api/todolist',
        scopes: [process.env.SCOPES || 'api://Enter_the_Web_Api_Application_Id_Here'],
    },
};

module.exports = {
    msalConfig,
    protectedResources,
};

msalConfig 物件包含一組設定選項,可用來自訂授權流程的行為。

authConfig.js 檔案中,取代:

  • Enter_the_Application_Id_Here 為您稍早所註冊用戶端精靈應用程式的應用程式 (用戶端) 識別碼。

  • Enter_the_Tenant_Subdomain_Here,並將其取代為目錄 (租用戶) 子網域。 例如,若租用戶主要網域是 contoso.onmicrosoft.com,請使用 contoso。 如果您沒有租用戶名稱,請了解如何讀取租用戶詳細資料

  • Enter_the_Client_Secret_Here 為您稍早複製的用戶端精靈應用程式祕密值。

  • Enter_the_Web_Api_Application_Id_Here 為您稍早所複製 Web API 應用程式的應用程式 (用戶端) 識別碼。

請注意,protectedResources 變數中的 scopes 屬性是您稍早所註冊 Web API 的資源識別碼 (應用程式識別碼 URI)。 完整的範圍 URI 看起來類似 api://Enter_the_Web_Api_Application_Id_Here/.default

取得存取權杖

在您的程式碼編輯器中,開啟 auth.js 檔案,然後新增下列程式碼:

const msal = require('@azure/msal-node');
const { msalConfig, protectedResources } = require('./authConfig');
/**
 * With client credentials flows permissions need to be granted in the portal by a tenant administrator.
 * The scope is always in the format '<resource-appId-uri>/.default'. For more, visit:
 * https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
 */
const tokenRequest = {
    scopes: [`${protectedResources.apiToDoList.scopes}/.default`],
};

const apiConfig = {
    uri: protectedResources.apiToDoList.endpoint,
};

/**
 * 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,
};

在程式碼中:

  • 準備 tokenRequestapiConfig 物件。 tokenRequest 包含您要求存取權杖的範圍。 範圍看起來像 api://Enter_the_Web_Api_Application_Id_Here/.defaultapiConfig 物件包含 Web API 的端點。 深入了解 OAuth 2.0 用戶端認證流程

  • 您可以將 msalConfig 物件傳遞至 ConfidentialClientApplication 類別的建構函式,以建立機密用戶端執行個體。

    const cca = new msal.ConfidentialClientApplication(msalConfig);
    
  • 您接著會使用 acquireTokenByClientCredential 函數來取得存取權杖。 您會在 getToken 函數中實作此邏輯:

    cca.acquireTokenByClientCredential(tokenRequest);
    

取得存取權杖之後,您可以繼續呼叫 API。

呼叫 API

在您的程式碼編輯器中,開啟 fetch.js 檔案,然後新增下列程式碼:

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
};

在此程式碼中,您會在要求 Authorization 標頭中以持有人權杖形式傳遞存取權杖來呼叫 Web API:

 Authorization: `Bearer ${accessToken}`

您會使用稍早在取得存取權杖中取得的存取權杖。

Web API 在收到要求之後,會對其進行評估,然後判斷其是否為應用程式要求。 如果存取權杖有效,則 Web API 會傳回所要求的資料。 否則,API 會傳回 401 Unauthorized HTTP 錯誤。

完成精靈應用程式

在您的程式碼編輯器中,開啟 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 'getToDos':
            try {
                const authResponse = await auth.getToken(auth.tokenRequest);
                const todos = await fetch.callApi(auth.apiConfig.uri, authResponse.accessToken);                
            } catch (error) {
                console.log(error);
            }

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

main();

此程式碼是您應用程式的進入點。 您使用可剖析程式庫的 yargs JavaScript 命令列引數,讓 Node.js 應用程式以互動方式擷取存取權杖,然後呼叫 API。 您使用稍早定義的 getTokencallApi 函數:

const authResponse = await auth.getToken(auth.tokenRequest);
const todos = await fetch.callApi(auth.apiConfig.uri, authResponse.accessToken);                

執行並測試精靈應用程式和 API

此時,您已準備好測試用戶端精靈應用程式和 Web API:

  1. 使用您在保護 ASP.NET Web API 教學課程中所學到的步驟來啟動 Web API。 您的 Web API 現在已準備好提供用戶端要求。 如果您未在 authConfig.js 檔案中所指定的連接埠 44351 上執行 Web API,請務必更新 authConfig.js 檔案,以使用正確的 Web API 連接埠號碼。

  2. 在您的終端機中,確定您位於包含精靈 Node.js 應用程式的專案資料夾中 (例如 ciam-call-api-node-daemon),然後執行下列命令:

    node . --op getToDos
    

如果您的精靈應用程式和 Web API 成功執行,則您應該會在主控台視窗中找到 Web API 端點 todos 變數所傳回的資料,與下列 JSON 陣列類似:

{
    id: 1,
    owner: '3e8....-db63-43a2-a767-5d7db...',
    description: 'Pick up grocery'
},
{
    id: 2,
    owner: 'c3cc....-c4ec-4531-a197-cb919ed.....',
    description: 'Finish invoice report'
},
{
    id: 3,
    owner: 'a35e....-3b8a-4632-8c4f-ffb840d.....',
    description: 'Water plants'
}

後續步驟