Tutorial: Llamada a la API de Microsoft Graph en una aplicación de demonio de consola de Node.js

En este tutorial, creará una aplicación de demonio de consola que llama a la API de Microsoft Graph mediante su propia identidad. La aplicación demonio de consola que cree usará la Biblioteca de autenticación de Microsoft (MSAL) para Node.js.

Siga los pasos de este tutorial para:

  • Registrar la aplicación en Azure Portal
  • Crear un proyecto de aplicación de demonio de consola de Node.js
  • Agregar la lógica de autenticación a la aplicación
  • Agregar detalles del registro de la aplicación
  • Agregar un método para llamar a una API web
  • Prueba de la aplicación

Requisitos previos

Registro de la aplicación

En primer lugar, complete los pasos descritos en Registro de una aplicación en la plataforma de identidad de Microsoft para registrar la aplicación.

Use la siguiente configuración para el registro de la aplicación:

  • Nombre: NodeDaemonApp (sugerido)
  • Tipos de cuenta admitidos: Solo las cuentas de este directorio organizativo
  • Permisos de API: API de Microsoft>Microsoft Graph>Permisos de la aplicación>User.Read.All
  • Secreto de cliente: ********* (registre este valor para usarlo en un paso posterior, se muestra solo una vez)

Creación del proyecto

  1. Empiece por crear un directorio para este proyecto de tutorial Node.js. Por ejemplo, NodeDaemonApp.

  2. En el terminal, cambie al directorio que creó (la raíz del proyecto) y ejecute los siguientes comandos:

    npm init -y
    npm install --save dotenv yargs axios @azure/msal-node
    
  3. A continuación, edite el archivo package.json en la raíz del proyecto y ponga y un prefijo al valor de main con bin/ de la forma siguiente:

    "main": "bin/index.js",
    
  4. Ahora cree el directorio bin y, dentro de bin, agregue el código siguiente a un nuevo archivo denominado 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();
    

El archivo index.js que acaba de crear hace referencia a otros dos módulos de nodo que creará a continuación:

  • auth.js: usa el nodo MSAL para adquirir tokens de acceso de la plataforma de identidad de Microsoft.
  • fetch.js: solicita datos de Microsoft Graph API mediante la inclusión de tokens de acceso (adquiridos en auth.js) en las solicitudes HTTP a la API.

Al final del tutorial, la estructura de archivos y directorios del proyecto debe tener un aspecto similar al siguiente:

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

Adición de la lógica de autenticación

Dentro del directorio bin, agregue el código siguiente a un nuevo archivo denominado auth.js. El código de auth.js adquiere un token de acceso de la plataforma de identidad de Microsoft para incluir en las solicitudes de 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:
 * https://learn.microsoft.com/azure/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
};

En el fragmento de código anterior, primero se crea un objeto de configuración (msalConfig) y se pasa para inicializar un objeto ConfidentialClientApplication de MSAL. A continuación, creamos un método para adquirir tokens a través de las credenciales del cliente y, por último, exponemos este módulo para que main.js pueda acceder a él. Los parámetros de configuración de este módulo se extraen de un archivo de entorno, que se creará en el paso siguiente.

Agregar detalles del registro de la aplicación

Cree un archivo de entorno para almacenar los detalles de registro de la aplicación que se usarán al adquirir tokens. Para ello, cree un archivo denominado .env dentro de la carpeta raíz del ejemplo (NodeDaemonApp) y agregue el código siguiente:

# 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/

Rellene estos detalles con los valores que se obtienen del portal de registro de aplicaciones de Azure:

  • Enter_the_Tenant_Id_here debe ser una de las siguientes:
    • Si la aplicación admite cuentas de este directorio organizativo, reemplace este valor por los valores de Id. de inquilino o Nombre de inquilino. Por ejemplo, contoso.microsoft.com.
    • Si la aplicación admite cuentas de cualquier directorio organizativo, reemplace este valor por organizations.
    • Si la aplicación admite cuentas de cualquier directorio organizativo y cuentas Microsoft personales, reemplace este valor por common.
    • Para restringir la compatibilidad a solo cuentas de Microsoft personales, reemplace este valor por consumers.
  • Enter_the_Application_Id_Here: el identificador de la aplicación (cliente) de la aplicación que registró.
  • Enter_the_Cloud_Instance_Id_Here: Instancia en la nube de Azure en la que se registra la aplicación.
    • En el caso de la nube principal (o global) de Azure, escriba https://login.microsoftonline.com.
    • En el caso de las nubes nacionales (por ejemplo, China), puede encontrar los valores adecuados en las nubes nacionales.
  • Enter_the_Graph_Endpoint_Here es la instancia de Microsoft Graph API con la que la aplicación debe comunicarse.
    • En el caso del punto de conexión de Microsoft Graph API global, reemplace ambas instancias de esta cadena por https://graph.microsoft.com.
    • Para obtener información sobre los puntos de conexión en las implementaciones de nubes nacionales, consulte Implementaciones de nube nacionales en la documentación de Microsoft Graph.

Agregar un método para llamar a una API web

Dentro de la carpeta bin, cree otro archivo denominado fetch.js y agregue el código siguiente para realizar llamadas de REST a 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.get(endpoint, options);
        return response.data;
    } catch (error) {
        console.log(error)
        return error;
    }
};

module.exports = {
    callApi: callApi
};

Aquí, el método callApi se usa para realizar una solicitud HTTP GET a un recurso protegido que requiere un token de acceso. A continuación, el método devuelve el contenido al autor de la llamada. Este método agrega el token adquirido al encabezado de autorización HTTP. Aquí, el recurso protegido es el punto de conexión de los usuarios de Microsoft Graph API, que muestra a los usuarios del inquilino donde se registra esta aplicación.

Prueba de la aplicación

Ha completado la creación de la aplicación y ya está listo para probar la funcionalidad de la aplicación.

Inicie la aplicación de demonio de la consola de Node.js mediante la ejecución del siguiente comando desde la raíz de la carpeta del proyecto:

node . --op getUsers

Esto debería producir alguna respuesta JSON de Microsoft Graph API y debería ver una matriz de objetos de usuario en la consola:

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://graph.microsoft.com/v1.0/$metadata#users',
    value: [
        {
            displayName: 'Adele Vance'
            givenName: 'Adele',
            jobTitle: 'Retail Manager',
            mail: 'AdeleV@msaltestingjs.onmicrosoft.com',
            mobilePhone: null,
            officeLocation: '18/2111',
            preferredLanguage: 'en-US',
            surname: 'Vance',
            userPrincipalName: 'AdeleV@msaltestingjs.onmicrosoft.com',
            id: '00aa00aa-bb11-cc22-dd33-44ee44ee44ee'
        }
    ]
}

Command-line interface displaying Graph response

Cómo funciona la aplicación

Esta aplicación usa la concesión de credenciales de cliente de OAuth 2.0. Este tipo de concesión se usa principalmente para las interacciones entre servidores que se deben ejecutar en segundo plano, sin la interacción inmediata con un usuario. El flujo de concesión de credenciales permite que un servicio web (cliente confidencial) use sus propias credenciales para autenticarse al llamar a otro servicio web, en lugar de suplantar a un usuario. El tipo de aplicaciones admitidas con este modelo de autenticación suele ser daemons o cuentas de servicio.

El ámbito que va a solicitar para un flujo de credenciales de cliente es el nombre del recurso seguido de /.default. Esta notación indica a Microsoft Entra ID que use los permisos de nivel de aplicación declarados estáticamente durante el registro de la aplicación. Además, un administrador de inquilinos debe conceder estos permisos de API.

Pasos siguientes

Si quiere profundizar más en el desarrollo de aplicaciones de demonio de Node.js en la Plataforma de identidad de Microsoft, consulte nuestra serie de escenarios dividida en varias partes: