Compartilhar via


Tutorial: Chamar uma API Web do aplicativo daemon .Node.js

Este tutorial demonstra como preparar seu Node.js aplicativo cliente daemon usando o fluxo de concessão de credenciais de cliente do OAuth (Open Authorization) 2.0 e configurá-lo para adquirir um token de acesso para chamar uma API Web. Você criará um aplicativo Node.js usando a MSAL (Biblioteca de Autenticação da Microsoft) para o Nó para simplificar a adição de autorização ao seu aplicativo.

Neste tutorial;

  • Configurar funções de aplicativo para a API Web
  • Conceder permissões ao aplicativo daemon
  • Crie um aplicativo Node.js no Visual Studio Code e instale dependências.
  • Habilite o aplicativo Node.js para adquirir um token de acesso para chamar uma API Web.

Pré-requisitos

  • Registre um novo aplicativo cliente no Centro de administração do Microsoft Entra, configurado para Contas em qualquer diretório organizacional e contas pessoais da Microsoft. Consulte Registrar um aplicativo para obter mais detalhes. Registre os seguintes valores na página visão geral do aplicativo para uso posterior:
    • ID do aplicativo (cliente)
    • ID do diretório (locatário)
    • Nome de domínio do diretório (locatário) (por exemplo, contoso.onmicrosoft.com ou contoso.com).
  • Adicione um segredo de cliente ao registro do aplicativo cliente. Não use segredos do cliente em aplicativos de produção. Em vez disso, use certificados ou credenciais federadas. Para obter mais informações, consulte adicionar credenciais ao seu aplicativo.
  • Uma API Web protegida que está em execução e pronta para aceitar solicitações. Certifique-se de que sua API Web expõe os seguintes endpoints por meio de HTTPS:
    • GET /api/todolist para obter todos os ToDos.
    • POST /api/todolist para adicionar um ToDo.
  • Node.js.
  • Embora qualquer IDE (ambiente de desenvolvimento integrado) que dê suporte a aplicativos React possa ser usado, este tutorial usa o Visual Studio Code.

Configurar funções de aplicativo

Uma API precisa publicar no mínimo uma função de aplicativo, também chamada permissão de aplicativo, para que os aplicativos clientes obtenham um token de acesso como eles mesmos. As permissões de aplicativo são o tipo de permissões que as APIs devem publicar quando desejam permitir que os aplicativos cliente se autentiquem com êxito como eles mesmos e não precisem conectar usuários. Para publicar uma permissão de aplicativo, siga estas etapas:

  1. Na página Registros de aplicativo, selecione o aplicativo que você criou (como ciam-ToDoList-api) para abrir sua página visão geral .

  2. Em Gerenciar, selecione funções de aplicativo.

  3. Selecione Criar função de aplicativo e, em seguida, insira os seguintes valores e, em seguida, selecione Aplicar para salvar suas alterações:

    Propriedade Valor
    Nome de exibição ToDoList.Read.All
    Tipos de membro permitidos Aplicativos
    Valor ToDoList.Read.All
    Descrição Permitir que o aplicativo leia a lista ToDo de cada usuário usando o 'TodoListApi'
    Quer habilitar esta função de aplicativo? Mantenha-o marcado
  4. Selecione Criar função de aplicativo novamente e, em seguida, insira os seguintes valores para a segunda função de aplicativo e selecione Aplicar para salvar suas alterações:

    Propriedade Valor
    Nome de exibição ToDoList.ReadWrite.All
    Tipos de membro permitidos Aplicativos
    Valor ToDoList.ReadWrite.All
    Descrição Permitir que o aplicativo leia e escreva a lista ToDo de cada usuário usando o 'ToDoListApi'
    Quer habilitar esta função de aplicativo? Mantenha-o marcado

Configurar uma declaração de token idtyp

Você pode adicionar a declaração opcional idtyp para ajudar a API Web a determinar se um token é um token de aplicativo ou um aplicativo + token de usuário. Embora você possa usar uma combinação de declarações scp e funções para a mesma finalidade, usar a declaração idtyp é a maneira mais fácil de diferenciar um token de aplicativo e um aplicativo + token de usuário. Por exemplo, o valor dessa declaração é app quando o token é um token somente de aplicativo.

Conceder permissões de API para o aplicativo daemon

  1. Na página Registros de aplicativo, selecione o aplicativo que você criou, como ciam-client-app.

  2. Em Gerenciar, selecione permissões de API.

  3. Em Permissões configuradas, selecione Adicionar uma permissão.

  4. Selecione a guia APIs que minha organização usa.

  5. Na lista de APIs, selecione a API, como ciam-ToDoList-api.

  6. Selecione a opção Permissões de aplicativo . Selecionamos essa opção quando o aplicativo faz login como ele mesmo, mas não em nome de um usuário.

  7. Na lista de permissões, selecione TodoList.Read.All, ToDoList.ReadWrite.All (use a caixa de pesquisa, se necessário).

  8. Selecione o botão Adicionar permissões .

  9. Neste ponto, você atribuiu as permissões corretamente. No entanto, como o aplicativo daemon não permite que os usuários interajam com ele, os próprios usuários não podem consentir com essas permissões. Para resolver esse problema, você, como administrador, deve consentir com essas permissões em nome de todos os usuários no locatário:

    1. Selecione Conceder consentimento do administrador para <o nome> do locatário e selecione Sim.
    2. Selecione Atualizar e verifique se Concedido para <nome do seu locatário> aparece em Status para as duas permissões.

Criar o projeto daemon do Node.js

Crie uma pasta para hospedar seu aplicativo daemon do Node.js, como ciam-call-api-node-daemon:

  1. No seu terminal, altere o diretório para a pasta do aplicativo daemon do Node, como cd ciam-call-api-node-daemon, e execute npm init -y. Esse comando cria um arquivo package.json padrão para seu projeto Node.js. Esse comando cria um arquivo package.json padrão para seu projeto Node.js.

  2. Crie pastas e arquivos adicionais para obter a seguinte estrutura de projeto:

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

Instalar dependências do aplicativo

No terminal, instale os pacotes axios, yargs e @azure/msal-node com o seguinte comando:

npm install axios yargs @azure/msal-node   

Criar objeto de configuração da MSAL

No editor de código, abra authConfig.js arquivo e adicione o seguinte 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,
};

O objeto msalConfig contém um conjunto de opções de configuração que você usará para personalizar o comportamento do fluxo de autorização.

No arquivo authConfig.js, substitua:

  • Enter_the_Application_Id_Here pela ID do aplicativo (cliente) do aplicativo daemon cliente que você registrou anteriormente.

  • Enter_the_Tenant_Subdomain_Here e substitua-o pelo subdomínio do Diretório (locatário). Por exemplo, se o domínio primário do locatário for contoso.onmicrosoft.com, use contoso. Se você não tiver o nome do locatário, saiba como ler os detalhes do locatário.

  • Enter_the_Client_Secret_Here pelo valor do segredo do aplicativo daemon cliente que você copiou anteriormente.

  • Enter_the_Web_Api_Application_Id_Here pela ID do aplicativo (cliente) do aplicativo de API Web que você copiou anteriormente.

Observe que a scopes propriedade na protectedResources variável é o identificador de recurso (URI da ID do aplicativo) da API Web que você registrou como parte dos pré-requisitos. O URI de escopo completo é semelhante a api://Enter_the_Web_Api_Application_Id_Here/.default.

Adquirir um token de acesso

No editor de código, abra o arquivo auth.js e adicione o seguinte 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,
};

No código:

  • Prepare os objetos tokenRequest e apiConfig. O tokenRequest contém o escopo para o qual você solicitará um token de acesso. O escopo se parece com api://Enter_the_Web_Api_Application_Id_Here/.default. O objeto apiConfig contém o endpoint para sua API Web. Saiba mais sobre o fluxo de credenciais do cliente OAuth 2.0.

  • Você criará uma instância de cliente confidencial passando o objeto msalConfig para o construtor da classe ConfidentialClientApplication.

    const cca = new msal.ConfidentialClientApplication(msalConfig);
    
  • Em seguida, usará a função acquireTokenByClientCredential para adquirir um token de acesso. Essa lógica será implementada na função getToken:

    cca.acquireTokenByClientCredential(tokenRequest);
    

Depois de adquirir um token de acesso, você pode prosseguir chamando uma API.

Chamar uma API

No editor de código, abra fetch.js arquivo e adicione o seguinte 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
};

Nesse código, você faz uma chamada para a API Web, passando o token de acesso como um token de portador no cabeçalho Authorization da solicitação:

 Authorization: `Bearer ${accessToken}`

Você usará o token de acesso adquirido anteriormente em Adquirir um token de acesso.

Depois que a API Web receber a solicitação, ela a avaliará e irá determinar que é uma solicitação de aplicativo. Se o token de acesso for válido, a API Web retornará os dados solicitados. Caso contrário, a API retornará um erro HTTP 401 Unauthorized.

Finalizar seu aplicativo daemon

No editor de código, abra o arquivo index.js e adicione o seguinte 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();

Esse código é o ponto de entrada para seu aplicativo. Você utiliza a biblioteca de análise de argumentos de linha de comando yargs JavaScript para aplicativos Node.js a fim de buscar interativamente um token de acesso e, em seguida, chamar a API. Você usará as funções getToken e callApi que definiu anteriormente:

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

Executar e testar o aplicativo daemon e a API

Neste ponto, você está pronto para testar seu aplicativo daemon cliente e a API Web:

  1. Use as etapas aprendidas no tutorial Proteger uma API Web ASP.NET para iniciar sua API Web. Sua API Web agora está pronta para atender às solicitações do cliente. Se você não executar sua API Web na porta 44351 conforme especificado no arquivo authConfig.js, atualize o arquivo authConfig.js para usar o número correto da porta da API Web.

  2. Em seu terminal, verifique se você está na pasta do projeto que contém o aplicativo daemon Node.js, como ciam-call-api-node-daemon, e execute o seguinte comando:

    node . --op getToDos
    

Se o aplicativo daemon e a API Web forem executados com sucesso, você deverá encontrar os dados retornados pela variável todos do ponto de extremidade da API Web, semelhantes à matriz JSON a seguir, na janela do seu console:

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

Próxima etapa