Compartir vía


Tutorial: Llame a una API web desde su aplicación daemon Node.js

Este tutorial es la parte final de una serie que muestra cómo preparar la aplicación cliente de demonio de Node.js mediante el flujo de concesión de credenciales de cliente de Open Authorization (OAuth) 2.0 y, a continuación, cómo configurarlo para adquirir un token de acceso para llamar a una API web. En la Parte 1 de esta serie, registró una API web y una aplicación de demonio en el Centro de administración de Microsoft Entra y concedió permisos. En este paso final se muestra cómo compilar una aplicación de Node.js mediante la Biblioteca de autenticación de Microsoft (MSAL) para Node para simplificar la adición de autorización a la aplicación.

En este tutorial,

  • Cree una aplicación de Node.js en Visual Studio Code y, a continuación, instale las dependencias.
  • Habilite la aplicación Node.js para adquirir un token de acceso para llamar a una API web.

Requisitos previos

Creación del proyecto demonio de Node.js

Cree una carpeta para hospedar la aplicación demonio de Node.js, como ciam-call-api-node-daemon:

  1. En el terminal, cambie el directorio a la carpeta de la aplicación demonio de Node, como cd ciam-call-api-node-daemon, y ejecute npm init -y. Este comando crea un archivo package.json predeterminado para el proyecto de Node.js. Este comando crea un archivo package.json predeterminado para el proyecto de Node.js.

  2. Cree carpetas y archivos adicionales para conseguir la siguiente estructura de proyecto:

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

Instalar las dependencias de la aplicación

En el terminal, ejecute este comando para instalar los paquetes axios, yargs y @azure/msal-node:

npm install axios yargs @azure/msal-node   

Creación de un objeto de configuración de MSAL

En el editor de código, abra el archivo authConfig.js y agregue el siguiente código:

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

El objeto msalConfig contiene un conjunto de opciones de configuración que se usan para personalizar el comportamiento de los flujos de autorización.

En el archivo authConfig.js, reemplace:

  • Enter_the_Application_Id_Here con el id. de aplicación (cliente) de la aplicación de demonio de cliente que registró anteriormente.

  • Enter_the_Tenant_Subdomain_Here y reemplácelo por el subdominio del directorio (inquilino). Por ejemplo, si el dominio principal del inquilino es contoso.onmicrosoft.com, use contoso. Si no tiene el nombre del inquilino, aprenda cómo leer los detalles del inquilino.

  • Enter_the_Client_Secret_Here con el valor del secreto de la aplicación de demonio de cliente que copió anteriormente.

  • Enter_the_Web_Api_Application_Id_Here con el id. de aplicación (cliente) de la aplicación API web que copió anteriormente.

Observe que la propiedad scopes de la variable protectedResources es el identificador de recurso (URI de id. de aplicación) de la API web que registró anteriormente. El URI de ámbito completo es similar a api://Enter_the_Web_Api_Application_Id_Here/.default.

Adquisición de un token de acceso

En el editor de código, abra el archivo auth.js y agregue el siguiente código:

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

En el código:

  • Prepare el objeto tokenRequest y apiConfig. tokenRequest contiene el ámbito para el que se solicita un token de acceso. El ámbito tiene un aspecto similar a api://Enter_the_Web_Api_Application_Id_Here/.default. El objeto apiConfig contiene el punto de conexión a la API web. Obtenga más información sobre el flujo de credenciales de cliente de OAuth 2.0.

  • Para crear una instancia de cliente confidencial, pase el objeto msalConfig al constructor de la clase ConfidentialClientApplication.

    const cca = new msal.ConfidentialClientApplication(msalConfig);
    
  • A continuación, use la función acquireTokenByClientCredential para adquirir un token de acceso. Esta lógica se implementa en la función getToken:

    cca.acquireTokenByClientCredential(tokenRequest);
    

Una vez que adquiera un token de acceso, puede continuar con la llamada a una API.

Llamar a una API

En el editor de código, abra el archivo fetch.js y agregue el siguiente código:

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

En este código, realizará una llamada a la API web pasando el token de acceso como token de portador en el encabezado Authorization de solicitud:

 Authorization: `Bearer ${accessToken}`

Use el token de acceso que adquirió anteriormente en Adquisición de un token de acceso.

Una vez que la API web recibe la solicitud, la evalúa y, a continuación, determina que es una solicitud de aplicación. Si el token de acceso es válido, la API web devuelve los datos solicitados. De lo contrario, la API devuelve un error HTTP 401 Unauthorized.

Finalización de la aplicación de demonio

En el editor de código, abra el archivo index.js y agregue el siguiente código:

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

Este código es el punto de entrada a la aplicación. Use la biblioteca de análisis de argumentos de línea de comandos yargs JavaScript para aplicaciones Node.js para capturar de manera interactiva un token de acceso y, a continuación, llamar a la API. Use las funciones getToken y callApi que definió anteriormente:

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

Ejecución y prueba de la aplicación y la API de demonio

En este momento, está listo para probar la aplicación de demonio cliente y la API web:

  1. Siga los pasos que aprendió en el tutorial Asegurar una API web ASP.NET para iniciar su API web. La API web ya está lista para atender solicitudes de cliente. Si no ejecuta su API web en el puerto 44351 especificado en el archivo authConfig.js, asegúrese de actualizar el archivo authConfig.js para utilizar el número de puerto correcto de la API web.

  2. En su terminal, asegúrese de que está en la carpeta del proyecto que contiene su aplicación daemon Node.js como ciam-call-api-node-daemon, luego ejecuta el siguiente comando:

    node . --op getToDos
    

Si su aplicación daemon y la API web se ejecutan correctamente, debería encontrar los datos devueltos por la variable todos del punto de conexión de la API web, similares a la siguiente matriz JSON, en su ventana de consola:

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

Paso siguiente