Partilhar via


Habilitar a autenticação em seu próprio aplicativo de página única usando o Azure AD B2C

Importante

A partir de 1º de maio de 2025, o Azure AD B2C não estará mais disponível para compra para novos clientes. Saiba mais nas nossas Perguntas Frequentes.

Este artigo mostra como adicionar a autenticação do Azure Ative Directory B2C (Azure AD B2C) ao seu próprio aplicativo de página única (SPA). Saiba como criar um aplicativo SPA usando a Biblioteca de Autenticação da Microsoft para JavaScript (MSAL.js).

Use este artigo com Configurar autenticação em um aplicativo SPA de exemplo, substituindo o aplicativo SPA de exemplo por seu próprio aplicativo SPA.

Visão geral

Este artigo usa o Node.js e o Express para criar um aplicativo Web Node.js básico. O Express é uma estrutura de aplicativo Web Node.js mínima e flexível que fornece um conjunto de recursos para aplicativos Web e móveis.

A biblioteca de autenticaçãoMSAL.js é uma biblioteca fornecida pela Microsoft que simplifica a adição de suporte de autenticação e autorização a aplicativos SPA.

Sugestão

Todo o código MSAL.js é executado no lado do cliente. Você pode substituir o código do lado do servidor Node.js e Express por outras soluções, como linguagens de script .NET Core, Java e Hypertext Preprocessor (PHP).

Pré-requisitos

Para revisar os pré-requisitos e as instruções de integração, consulte Configurar a autenticação em um aplicativo SPA de exemplo.

Etapa 1: Criar um projeto de aplicativo SPA

Você pode usar um projeto de aplicativo SPA existente ou criar um novo. Para criar um novo projeto, faça o seguinte:

  1. Abra um shell de comando e crie um novo diretório (por exemplo, myApp). Esse diretório conterá o código do aplicativo, a interface do usuário e os arquivos de configuração.

  2. Insira o diretório que você criou.

  3. Use o npm init comando para criar um package.json arquivo para seu aplicativo. Este comando solicita informações sobre seu aplicativo (por exemplo, o nome e a versão do aplicativo e o nome do ponto de entrada inicial, o arquivo index.js ). Execute o seguinte comando e aceite os valores padrão:

npm init

Etapa 2: Instalar as dependências

Para instalar o pacote Express, no shell de comando, execute o seguinte comando:

npm install express

Para localizar os arquivos estáticos do aplicativo, o código do lado do servidor usa o pacote Path .

Para instalar o pacote Path, no shell de comando, execute o seguinte comando:

npm install path

Etapa 3: Configurar o servidor Web

Na pasta myApp , crie um arquivo chamado index.js, que contém o seguinte código:

// Initialize express
const express = require('express');
const app = express();

// The port to listen to incoming HTTP requests
const port = 6420;

// Initialize path
const path = require('path');

// Set the front-end folder to serve public assets.
app.use(express.static('App'));

// Set up a route for the index.html
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/index.html'));
});

// Start the server, and listen for HTTP requests
app.listen(port, () => {
  console.log(`Listening on http://localhost:${port}`);
});

Etapa 4: Criar a interface do usuário do SPA

Adicione o ficheiro do aplicativo SPA index.html. Esse arquivo implementa uma interface de usuário criada com uma estrutura de Bootstrap e importa arquivos de script para configuração, autenticação e chamadas de API da Web.

Os recursos referenciados pelo arquivo index.html são detalhados na tabela a seguir:

Referência Definição
MSAL.js biblioteca Caminho CDN da biblioteca JavaScript de autenticação MSAL.js.
Folha de estilo do Bootstrap Uma estrutura de front-end gratuita para um desenvolvimento web mais rápido e fácil. A estrutura inclui modelos de design baseados em HTML e CSS.

Para renderizar o arquivo de índice SPA, na pasta myApp , crie um arquivo chamado index.html, que contém o seguinte trecho HTML:

<!DOCTYPE html>
<html>
    <head>
        <title>My Azure AD B2C test app</title>
    </head>
    <body>
        <h2>My Azure AD B2C test app</h2>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
        <button type="button" id="signIn" class="btn btn-secondary" onclick="signIn()">Sign-in</button>
        <button type="button" id="signOut" class="btn btn-success d-none" onclick="signOut()">Sign-out</button>
        <h5 id="welcome-div" class="card-header text-center d-none"></h5>
        <br />
        <!-- Content -->
        <div class="card">
            <div class="card-body text-center">
                <pre id="response" class="card-text"></pre>
                <button type="button" id="callApiButton" class="btn btn-primary d-none" onclick="passTokenToApi()">Call API</button>
            </div>
        </div>
        <script src="https://alcdn.msauth.net/browser/2.14.2/js/msal-browser.min.js" integrity="sha384-ggh+EF1aSqm+Y4yvv2n17KpurNcZTeYtUZUvhPziElsstmIEubyEB6AIVpKLuZgr" crossorigin="anonymous"></script>

        <!-- Importing app scripts (load order is important) -->
        <script type="text/javascript" src="./apiConfig.js"></script>
        <script type="text/javascript" src="./policies.js"></script>
        <script type="text/javascript" src="./authConfig.js"></script>
        <script type="text/javascript" src="./ui.js"></script>

        <!-- <script type="text/javascript" src="./authRedirect.js"></script>   -->
        <!-- uncomment the above line and comment the line below if you would like to use the redirect flow -->
        <script type="text/javascript" src="./authRedirect.js"></script>
        <script type="text/javascript" src="./api.js"></script>
    </body>
</html>

Etapa 5: Configurar a biblioteca de autenticação

Configure como a biblioteca de MSAL.js se integra ao Azure AD B2C. A biblioteca MSAL.js utiliza um objeto de configuração comum para se conectar aos pontos de extremidade de autenticação do tenant no Azure AD B2C.

Para configurar a biblioteca de autenticação, faça o seguinte:

  1. Na pasta myApp , crie uma nova pasta chamada App.

  2. Dentro da pasta Aplicativo , crie um novo arquivo chamado authConfig.js.

  3. Adicione o seguinte código JavaScript ao arquivo authConfig.js :

    const msalConfig = {
        auth: {
        clientId: "<Application-ID>", 
        authority: b2cPolicies.authorities.signUpSignIn.authority, 
        knownAuthorities: [b2cPolicies.authorityDomain], 
        redirectUri: "http://localhost:6420",
        },
        cache: {
        cacheLocation: "localStorage", .
        storeAuthStateInCookie: false, 
        }
    };
    
    const loginRequest = {
    scopes: ["openid", ...apiConfig.b2cScopes],
    };
    
    const tokenRequest = {
    scopes: [...apiConfig.b2cScopes],
    forceRefresh: false
    };
    
  4. Substitua <Application-ID> pelo ID de registo da aplicação. Para obter mais informações, consulte Configurar a autenticação em um aplicativo SPA de exemplo.

Sugestão

Para obter mais opções de configuração de objeto MSAL, consulte o artigo Opções de autenticação .

Etapa 6: Especificar seus fluxos de usuário do Azure AD B2C

Crie o arquivo policies.js , que fornece informações sobre seu ambiente do Azure AD B2C. A biblioteca de MSAL.js usa essas informações para criar solicitações de autenticação para o Azure AD B2C.

Para especificar seus fluxos de usuário do Azure AD B2C, faça o seguinte:

  1. Dentro da pasta Aplicativo , crie um novo arquivo chamado policies.js.

  2. Adicione o seguinte código ao arquivo policies.js :

    const b2cPolicies = {
        names: {
            signUpSignIn: "B2C_1_SUSI",
            editProfile: "B2C_1_EditProfile"
        },
        authorities: {
            signUpSignIn: {
                authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-SignInOrSignUp-Policy-Id",
            },
            editProfile: {
                authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-EditProfile-Policy-Id"
            }
        },
        authorityDomain: "contoso.b2clogin.com"
    }
    
  3. Substitua B2C_1_SUSI pelo nome da política de entrada do Azure AD B2C.

  4. Substitua B2C_1_EditProfile pelo nome da política do Azure AD B2C do seu perfil de edição.

  5. Substitua todas as instâncias de contoso pelo seu nome do tenant do Azure AD B2C.

Etapa 7: Usar o MSAL para entrar no usuário

Nesta etapa, implemente os métodos para inicializar o fluxo de entrada, a aquisição de token de acesso à API e os métodos de saída.

Para obter mais informações, consulte o artigo Usar a Biblioteca de Autenticação da Microsoft (MSAL) para entrar no usuário .

Para entrar no usuário, faça o seguinte:

  1. Dentro da pasta Aplicativo , crie um novo arquivo chamado authRedirect.js.

  2. No seu authRedirect.js, copie e cole o seguinte código:

    // Create the main myMSALObj instance
    // configuration parameters are located at authConfig.js
    const myMSALObj = new msal.PublicClientApplication(msalConfig);
    
    let accountId = "";
    let idTokenObject = "";
    let accessToken = null;
    
    myMSALObj.handleRedirectPromise()
        .then(response => {
            if (response) {
                /**
                 * For the purpose of setting an active account for UI update, we want to consider only the auth response resulting
                 * from SUSI flow. "tfp" claim in the id token tells us the policy (NOTE: legacy policies may use "acr" instead of "tfp").
                 * To learn more about B2C tokens, visit https://v4.hkg1.meaqua.org/azure/active-directory-b2c/tokens-overview
                 */
                if (response.idTokenClaims['tfp'].toUpperCase() === b2cPolicies.names.signUpSignIn.toUpperCase()) {
                    handleResponse(response);
                }
            }
        })
        .catch(error => {
            console.log(error);
        });
    
    
    function setAccount(account) {
        accountId = account.homeAccountId;
        idTokenObject = account.idTokenClaims;
        myClaims= JSON.stringify(idTokenObject);
        welcomeUser(myClaims);
    }
    
    function selectAccount() {
    
        /**
         * See here for more information on account retrieval: 
         * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
         */
    
        const currentAccounts = myMSALObj.getAllAccounts();
    
        if (currentAccounts.length < 1) {
            return;
        } else if (currentAccounts.length > 1) {
    
            /**
             * Due to the way MSAL caches account objects, the auth response from initiating a user-flow
             * is cached as a new account, which results in more than one account in the cache. Here we make
             * sure we are selecting the account with homeAccountId that contains the sign-up/sign-in user-flow, 
             * as this is the default flow the user initially signed-in with.
             */
            const accounts = currentAccounts.filter(account =>
                account.homeAccountId.toUpperCase().includes(b2cPolicies.names.signUpSignIn.toUpperCase())
                &&
                account.idTokenClaims.iss.toUpperCase().includes(b2cPolicies.authorityDomain.toUpperCase())
                &&
                account.idTokenClaims.aud === msalConfig.auth.clientId 
                );
    
            if (accounts.length > 1) {
                // localAccountId identifies the entity for which the token asserts information.
                if (accounts.every(account => account.localAccountId === accounts[0].localAccountId)) {
                    // All accounts belong to the same user
                    setAccount(accounts[0]);
                } else {
                    // Multiple users detected. Logout all to be safe.
                    signOut();
                };
            } else if (accounts.length === 1) {
                setAccount(accounts[0]);
            }
    
        } else if (currentAccounts.length === 1) {
            setAccount(currentAccounts[0]);
        }
    }
    
    // in case of page refresh
    selectAccount();
    
    async function handleResponse(response) {
    
        if (response !== null) {
            setAccount(response.account);
        } else {
            selectAccount();
        }
    }
    
    function signIn() {
        myMSALObj.loginRedirect(loginRequest);
    }
    
    function signOut() {
        const logoutRequest = {
            postLogoutRedirectUri: msalConfig.auth.redirectUri,
        };
    
        myMSALObj.logoutRedirect(logoutRequest);
    }
    
    function getTokenRedirect(request) {
        request.account = myMSALObj.getAccountByHomeId(accountId); 
    
        return myMSALObj.acquireTokenSilent(request)
            .then((response) => {
                // In case the response from B2C server has an empty accessToken field
                // throw an error to initiate token acquisition
                if (!response.accessToken || response.accessToken === "") {
                    throw new msal.InteractionRequiredAuthError;
                } else {
                    console.log("access_token acquired at: " + new Date().toString());
                    accessToken = response.accessToken;
                    passTokenToApi();
                }
            }).catch(error => {
                console.log("Silent token acquisition fails. Acquiring token using popup. \n", error);
                if (error instanceof msal.InteractionRequiredAuthError) {
                    // fallback to interaction when silent call fails
                    return myMSALObj.acquireTokenRedirect(request);
                } else {
                    console.log(error);   
                }
        });
    }
    
    // Acquires and access token and then passes it to the API call
    function passTokenToApi() {
        if (!accessToken) {
            getTokenRedirect(tokenRequest);
        } else {
            try {
                callApi(apiConfig.webApi, accessToken);
            } catch(error) {
                console.log(error); 
            }
        }
    }
    
    function editProfile() {
    
    
        const editProfileRequest = b2cPolicies.authorities.editProfile;
        editProfileRequest.loginHint = myMSALObj.getAccountByHomeId(accountId).username;
    
        myMSALObj.loginRedirect(editProfileRequest);
    }
    

Etapa 8: Configurar o local e o escopo da API Web

Para permitir que seu aplicativo SPA chame uma API da Web, forneça o local do ponto de extremidade da API da Web e os escopos a serem usados para autorizar o acesso à API da Web.

Para configurar o local e os escopos da API Web, faça o seguinte:

  1. Dentro da pasta Aplicativo , crie um novo arquivo chamado apiConfig.js.

  2. No seu apiConfig.js, copie e cole o seguinte código:

    // The current application coordinates were pre-registered in a B2C tenant.
    const apiConfig = {
        b2cScopes: ["https://contoso.onmicrosoft.com/tasks/tasks.read"],
        webApi: "https://mydomain.azurewebsites.net/tasks"
    };
    
  3. Substitua contoso pelo nome do locatário. O nome do escopo necessário pode ser encontrado conforme descrito no artigo Configurar escopos .

  4. Substitua o valor por webApi pelo local do endpoint da sua API da Web.

Etapa 9: Chame sua API da Web

Defina a solicitação HTTP para seu ponto de extremidade da API. A solicitação HTTP é configurada para inserir o token de acesso adquirido com MSAL.js no cabeçalho HTTP da solicitação.

O código seguinte define o pedido HTTP GET para o ponto de acesso da API, passando o token de acesso no Authorization cabeçalho HTTP. O local da webApi API é definido pela chave em apiConfig.js.

Para chamar sua API da Web usando o token adquirido, faça o seguinte:

  1. Dentro da pasta Aplicativo , crie um novo arquivo chamado api.js.

  2. Adicione o seguinte código ao arquivo api.js :

    function callApi(endpoint, token) {
    
        const headers = new Headers();
        const bearer = `Bearer ${token}`;
    
        headers.append("Authorization", bearer);
    
        const options = {
            method: "GET",
            headers: headers
        };
    
        logMessage('Calling web API...');
    
        fetch(endpoint, options)
        .then(response => response.json())
        .then(response => {
    
            if (response) {
            logMessage('Web API responded: ' + response.name);
            }
    
            return response;
        }).catch(error => {
            console.error(error);
        });
    }
    

Etapa 10: Adicionar a referência de elementos da interface do usuário

O aplicativo SPA usa JavaScript para controlar os elementos da interface do usuário. Por exemplo, exibe os botões de iniciar e terminar sessão e exibe as afirmações do token de ID dos utilizadores no ecrã.

Para adicionar a referência de elementos da interface do usuário, faça o seguinte:

  1. Dentro da pasta Aplicativo , crie um arquivo chamado ui.js.

  2. Adicione o seguinte código ao arquivo ui.js :

    // Select DOM elements to work with
    const signInButton = document.getElementById('signIn');
    const signOutButton = document.getElementById('signOut')
    const titleDiv = document.getElementById('title-div');
    const welcomeDiv = document.getElementById('welcome-div');
    const tableDiv = document.getElementById('table-div');
    const tableBody = document.getElementById('table-body-div');
    const editProfileButton = document.getElementById('editProfileButton');
    const callApiButton = document.getElementById('callApiButton');
    const response = document.getElementById("response");
    const label = document.getElementById('label');
    
    function welcomeUser(claims) {
        welcomeDiv.innerHTML = `Token claims: </br></br> ${claims}!`
    
        signInButton.classList.add('d-none');
        signOutButton.classList.remove('d-none');
        welcomeDiv.classList.remove('d-none');
        callApiButton.classList.remove('d-none');
    }
    
    function logMessage(s) {
        response.appendChild(document.createTextNode('\n' + s + '\n'));
    }
    

Etapa 11: Executar seu aplicativo SPA

No shell de comando, execute os seguintes comandos:

npm install  
npm ./index.js
  1. Ir para https://localhost:6420.
  2. Selecione Iniciar sessão.
  3. Conclua o processo de inscrição ou login.

Depois de autenticar-se com êxito, o token de ID analisado é exibido no ecrã. Selecione Call API para invocar o ponto de extremidade da API.

Próximos passos