Ativar a autenticação na sua própria aplicação de página única com o Azure AD B2C
Este artigo mostra-lhe como adicionar a autenticação do Azure Active Directory B2C (Azure AD B2C) à sua própria aplicação de página única (SPA). Saiba como criar uma aplicação SPA com a Biblioteca de Autenticação da Microsoft para JavaScript (MSAL.js).
Utilize este artigo com Configurar a autenticação numa aplicação SPA de exemplo, substituindo a aplicação SPA de exemplo pela sua própria aplicação SPA.
Descrição Geral
Este artigo utiliza o Node.js e o Express para criar uma aplicação Web de Node.js básica. O Express é uma arquitetura de aplicações Web de Node.js mínima e flexível que fornece um conjunto de funcionalidades para aplicações 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 aplicações SPA.
Dica
Todo o código MSAL.js é executado no lado do cliente. Pode substituir o Node.js e o código do lado do servidor Express por outras soluções, como linguagens de scripting .NET Core, Java e Pré-processamento de Hypertext (PHP).
Pré-requisitos
Para rever os pré-requisitos e as instruções de integração, veja Configurar a autenticação numa aplicação SPA de exemplo.
Passo 1: criar um projeto de aplicação SPA
Pode utilizar um projeto de aplicação SPA existente ou criar um novo. Para criar um novo projeto, faça o seguinte:
Abra uma shell de comandos e crie um novo diretório (por exemplo, myApp). Este diretório irá conter o código da aplicação, a interface de utilizador e os ficheiros de configuração.
Introduza o diretório que criou.
Utilize o
npm init
comando para criar umpackage.json
ficheiro para a sua aplicação. Este comando pede-lhe informações sobre a sua aplicação (por exemplo, o nome e a versão da sua aplicação e o nome do ponto de entrada inicial, o ficheiro index.js ). Execute o seguinte comando e aceite os valores predefinidos:
npm init
Passo 2: Instalar as dependências
Para instalar o pacote Express, na shell de comandos, execute o seguinte comando:
npm install express
Para localizar os ficheiros estáticos da aplicação, o código do lado do servidor utiliza o pacote Path .
Para instalar o pacote Path, na shell de comandos, execute o seguinte comando:
npm install path
Passo 3: Configurar o servidor Web
Na sua pasta myApp , crie um ficheiro com o nome 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}`);
});
Passo 4: criar a interface de utilizador spa
Adicione o ficheiro da aplicação index.html
SPA. Este ficheiro implementa uma interface de utilizador criada com uma arquitetura Bootstrap e importa ficheiros de script para configuração, autenticação e chamadas à API Web.
Os recursos referenciados pelo ficheiro index.html estão detalhados na tabela seguinte:
Referência | Definição |
---|---|
biblioteca de MSAL.js | MSAL.js caminho da CDN da biblioteca JavaScript de autenticação. |
Folha de estilos bootstrap | Uma arquitetura de front-end gratuita para um desenvolvimento Web mais rápido e fácil. A arquitetura inclui modelos de estrutura baseados em HTML e baseados em CSS. |
policies.js |
Contém o Azure AD políticas personalizadas B2C e fluxos de utilizador. |
authConfig.js |
Contém parâmetros de configuração de autenticação. |
authRedirect.js |
Contém a lógica de autenticação. |
apiConfig.js |
Contém âmbitos da API Web e a localização do ponto final da API. |
api.js |
Define o método a utilizar para chamar a sua API e processar a respetiva resposta. |
ui.js |
Controla os elementos da IU. |
Para compor o ficheiro de índice SPA, na pasta myApp , crie um ficheiro com o nomeindex.html, que contém o seguinte fragmento 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>
Passo 5: Configurar a biblioteca de autenticação
Configure a forma como a biblioteca de MSAL.js se integra no Azure AD B2C. A biblioteca de MSAL.js utiliza um objeto de configuração comum para ligar ao seu Azure AD pontos finais de autenticação do inquilino B2C.
Para configurar a biblioteca de autenticação, faça o seguinte:
Na pasta myApp , crie uma nova pasta denominada Aplicação.
Na pasta Aplicação , crie um novo ficheiro com o nomeauthConfig.js.
Adicione o seguinte código JavaScript ao ficheiro 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 };
Substitua pelo
<Application-ID>
ID da aplicação de registo de aplicações. Para obter mais informações, veja Configurar a autenticação numa aplicação SPA de exemplo.
Dica
Para obter mais opções de configuração de objetos MSAL, veja o artigo Opções de autenticação .
Passo 6: Especificar os fluxos de utilizador Azure AD B2C
Crie o ficheiro policies.js, que fornece informações sobre o seu ambiente Azure AD B2C. A biblioteca de MSAL.js utiliza estas informações para criar pedidos de autenticação para Azure AD B2C.
Para especificar os fluxos de utilizador Azure AD B2C, faça o seguinte:
Na pasta Aplicação , crie um novo ficheiro com o nomepolicies.js.
Adicione o seguinte código ao ficheiro 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" }
Substitua pelo
B2C_1_SUSI
seu início de sessão Azure AD nome da Política B2C.Substitua pelo
B2C_1_EditProfile
seu perfil de edição Azure AD nome da política B2C.Substitua todas as instâncias de
contoso
pelo seu nome de inquilino Azure AD B2C.
Passo 7: utilizar o MSAL para iniciar sessão no utilizador
Neste passo, implemente os métodos para inicializar o fluxo de início de sessão, a aquisição de tokens de acesso à API e os métodos de fim de sessão.
Para obter mais informações, consulte o artigo Utilizar a Biblioteca de Autenticação da Microsoft (MSAL) para iniciar sessão no utilizador .
Para iniciar sessão no utilizador, faça o seguinte:
Na pasta Aplicação , crie um novo ficheiro com o nomeauthRedirect.js.
No 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://learn.microsoft.com/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); }
Passo 8: Configurar a localização e o âmbito da API Web
Para permitir que a aplicação SPA chame uma API Web, forneça a localização do ponto final da API Web e os âmbitos a utilizar para autorizar o acesso à API Web.
Para configurar a localização e os âmbitos da API Web, faça o seguinte:
Na pasta Aplicação , crie um novo ficheiro com o nomeapiConfig.js.
No 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" };
Substitua pelo
contoso
nome do seu inquilino. O nome de âmbito necessário pode ser encontrado conforme descrito no artigo Configurar âmbitos .Substitua o valor para pela
webApi
localização do ponto final da API Web.
Passo 9: Chamar a API Web
Defina o pedido HTTP para o ponto final da API. O pedido HTTP está configurado para transmitir o token de acesso que foi adquirido com MSAL.js para o Authorization
cabeçalho HTTP no pedido.
O código seguinte define o pedido HTTP GET
para o ponto final da API ao transmitir o token de acesso no Authorization
cabeçalho HTTP. A localização da webApi
API é definida pela chave no apiConfig.js.
Para chamar a API Web com o token que adquiriu, faça o seguinte:
Na pasta Aplicação , crie um novo ficheiro com o nomeapi.js.
Adicione o seguinte código ao ficheiro 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); }); }
Passo 10: adicionar a referência de elementos da IU
A aplicação SPA utiliza JavaScript para controlar os elementos da IU. Por exemplo, apresenta os botões de início de sessão e de início de sessão e compõe as afirmações de token de ID dos utilizadores no ecrã.
Para adicionar a referência de elementos da IU, faça o seguinte:
Dentro da pasta Aplicação , crie um ficheiro com o nomeui.js.
Adicione o seguinte código ao ficheiro 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')); }
Passo 11: Executar a aplicação SPA
Na shell de comandos, execute os seguintes comandos:
npm install
npm ./index.js
- Ir para https://localhost:6420.
- Selecione Iniciar sessão.
- Conclua o processo de inscrição ou início de sessão.
Depois de autenticar com êxito, o token de ID analisado é apresentado no ecrã. Selecione Call API
para chamar o ponto final da API.
Passos seguintes
- Saiba mais sobre o exemplo de código.
- Configure as opções de Autenticação na sua própria aplicação SPA com Azure AD B2C.
- Ative a autenticação na sua própria API Web.