Inicio rápido: registrar y configurar una aplicación SPA para Dataverse usando msal.js
En este tema se describe el proceso para registrar y configurar la Aplicación de una sola página (SPA) más sencilla para tener acceso a los datos en Microsoft Dataverse mediante msal.js y el uso compartido de recursos de origen cruzado(CORS). Más información: Usar OAuth con uso compartido de recursos entre orígenes para conectar una aplicación de una sola página a Dataverse.
Requisitos previos
Acceda a un entorno de Dataverse.
Una cuenta de Azure con una suscripción activa.
La cuenta de Azure debe tener permiso para administrar aplicaciones en Microsoft Entra ID. Cualquiera de los roles siguientes de Microsoft Entra ID incluyen los permisos obligatorios:
Visual Studio Code (VS Code) Descargar
Objetivo de este inicio rápido
Al completar este inicio rápido podrá ejecutar una aplicación SPA sencilla que proporcione la capacidad para que un usuario se autentique y recupere datos de Dataverse.
Cuando se depura la aplicación inicialmente solo habrá un botón Iniciar sesión.
Haga clic en Iniciar sesión y se abrirá una ventana emergente para ingresar sus credenciales.
Tras escribir sus credenciales encontrará que el botón Iniciar sesión está oculto y un botón Cerrar sesión y Obtener cuentas están visibles. También verá un saludo con información de su cuenta de usuario.
Haga clic en el botón Obtener cuentas para recuperar 10 registros de cuenta de su organización de Dataverse. El resultado se muestra en la captura de pantalla siguiente:
Por último, puede hacer clic en el botón Cerrar sesión para cerrar la sesión.
Nota
Esta aplicación SPA no está diseñada para representar un modelo para desarrollar aplicaciones SPA robustas. Está simplificada para centrarse en el proceso de registrar y configurar la aplicación.
Conseguir el punto de conexión de API web de Dataverse
Use las instrucciones en Ver recursos para desarrolladores para identificar un extremo de la API web para un entorno al que pueda acceder. Debería tener aspecto similar a éste: https://yourorg.api.crm.dynamics.com/api/data/v9.2
Registrar su aplicación
Desde el centro de administración Power Platform en la navegación izquierda expanda Centros de administración y seleccione Microsoft Entra ID.
Esto abre el Centro de administración de Microsoft Entra
Expanda Aplicaciones y seleccione Registros de aplicaciones.
Haga clic en Nuevo registro. Esto abrirá el formulario Registrar una aplicación.
En el formulario Registrar una aplicación, escriba un Nombre. A los efectos de esta guía de inicio rápido, utilice el nombre SPA sencillo.
Para Tipos de cuenta admitidos, la selección predeterminada debe ser:
Solo cuentas de este directorio organizativo (solo de <nombre de inquilino>: inquilino único). No cambie esto.Para URI de redirección (opcional), utilice estas opciones:
- Seleccione una plataforma: solicitud de una sola página (SPA)
e.g. https://example.com/auth
:http://localhost:5500/index.html
Haga clic en Registrar.
En el área Visión general, copie los siguientes valores porque los necesitará en el paso final de Crear un proyecto de aplicación web.
- Identificador de aplicación (cliente)
- Id. de de directorio (inquilino)
Seleccione Permisos de API.
Haga clic en Agregar permisos.
En el menú desplegable Solicitar permisos de API, seleccione Dynamics CRM.
- Si no ve Dynamics CRM, busque Dataverse. O bien, seleccione la pestaña API que usa mi organización y busque Dataverse.
Seleccione el permiso delegado person_impersonation.
Haga clic en Agregar permisos.
Cuando finalice los permisos configurados deberían tener este aspecto:
Instalar la extensión Live Server de Visual Studio Code
Live Server es una extensión de Visual Studio Code que le permite lanzar fácilmente un servidor de desarrollo local para páginas web.
Utilice estas instrucciones para buscar e instalar la extensión Live Server para VS Code en el mercado de VS Code:
Una vez que haya instalado la extensión Live Server, realice estos cambios en la configuración predeterminada.
Haga clic en el icono de engranaje en VS Code y seleccione Ajustes o utilice el atajo de teclado
Ctrl+,
.En la ventana de búsqueda, escriba
liveServer.settings.host
y cambie el valor predeterminado de127.0.0.1
alocalhost
.
Crear un proyecto de aplicación web
Cree una carpeta en su equipo. El nombre no es importante, pero a los efectos de estas instrucciones, asígnele el nombre
simplespa
.Abra VS Code y seleccione Archivo > Abrir carpeta en el menú. Seleccione la carpeta
simplespa
.Cree un nuevo archivo HTML en la carpeta llamada
index.html
. (Noindex.htm
)Copie el contenido a continuación en el archivo index.html:
<html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script> const baseUrl = "https://org.api.crm.dynamics.com"; //<= Change this const clientId = "11111111-1111-1111-1111-111111111111"; //<= Change this const tenantId = "22222222-2222-2222-2222-222222222222"; //<= Change this const redirectUrl = "http://localhost:5500/index.html"; const webAPIEndpoint = baseUrl +"/api/data/v9.2"; // Configuration object to be passed to MSAL instance on creation. const msalConfig = { auth: { clientId: clientId, // Full directory URL, in the form of https://login.microsoftonline.com/<tenant-id> authority: "https://login.microsoftonline.com/"+tenantId, redirectUri: redirectUrl, }, cache: { cacheLocation: "sessionStorage" // This configures where your cache will be stored }, system: { loggerOptions: { loggerCallback: (level, message, containsPii) => { if (containsPii) { return; } switch (level) { case msal.LogLevel.Error: console.error(message); return; case msal.LogLevel.Info: console.info(message); return; case msal.LogLevel.Verbose: console.debug(message); return; case msal.LogLevel.Warning: console.warn(message); return; } } } } }; </script> <!-- Latest version of msal-browser.js from CDN as of 2022/09 --> <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.28.1/js/msal-browser.min.js"> </script> <style> body { font-family: 'Segoe UI'; } table { border-collapse: collapse; } td, th { border: 1px solid black; } #message { color: green; } </style> </head> <body> <div> <button id="loginButton" onclick="signIn()">Login</button> <button id="logoutButton" onclick="signOut()" style="display:none;">Logout</button> <button id="getAccountsButton" onclick="getAccounts(writeTable)" style="display:none;">Get Accounts</button> <div id="message"></div> <table id="accountsTable" style="display:none;"> <thead><tr><th>Name</th><th>City</th></tr></thead> <tbody id="accountsTableBody"></tbody> </table> </div> <script> const loginButton = document.getElementById("loginButton"); const logoutButton = document.getElementById("logoutButton"); const getAccountsButton = document.getElementById("getAccountsButton"); const accountsTable = document.getElementById("accountsTable"); const accountsTableBody = document.getElementById("accountsTableBody"); const message = document.getElementById("message"); // Create the main myMSALObj instance const myMSALObj = new msal.PublicClientApplication(msalConfig); let username = ""; // Sets the username. Called at the end of this script. function selectAccount() { const currentAccounts = myMSALObj.getAllAccounts(); if (currentAccounts.length === 0) { return; } else if (currentAccounts.length > 1) { // Add choose account code here console.warn("Multiple accounts detected."); } else if (currentAccounts.length === 1) { username = currentAccounts[0].username; showWelcomeMessage(username); } } // Called by the loginButton function signIn() { myMSALObj.loginPopup({ scopes: ["User.Read",baseUrl+"/user_impersonation"] //<= Includes Dataverse scope }) .then(response =>{ if (response !== null) { username = response.account.username; showWelcomeMessage(username); } else { selectAccount(); } }) .catch(error => { console.error(error); }); } // Shows greeting and enables logoutButton and getAccountsButton // Called from signIn or selectAccount functions function showWelcomeMessage(username) { message.innerHTML = `Welcome ${username}`; loginButton.style.display = "none"; logoutButton.style.display = "block"; getAccountsButton.style.display = "block"; } // Called by the logoutButton function signOut() { const logoutRequest = { account: myMSALObj.getAccountByUsername(username), postLogoutRedirectUri: msalConfig.auth.redirectUri, mainWindowRedirectUri: msalConfig.auth.redirectUri }; myMSALObj.logoutPopup(logoutRequest); } // Provides the access token for a request, opening pop-up if necessary. // Used by GetAccounts function function getTokenPopup(request) { request.account = myMSALObj.getAccountByUsername(username); return myMSALObj.acquireTokenSilent(request) .catch(error => { console.warn("Silent token acquisition fails. Acquiring token using popup"); if (error instanceof msal.InteractionRequiredAuthError) { // fallback to interaction when silent call fails return myMSALObj.acquireTokenPopup(request) .then(tokenResponse => { console.log(tokenResponse); return tokenResponse; }).catch(error => { console.error(error); }); } else { console.warn(error); } }); } // Retrieves top 10 account records from Dataverse function getAccounts(callback) { // Gets the access token getTokenPopup({ scopes: [baseUrl+"/.default"] }) .then(response => { getDataverse("accounts?$select=name,address1_city&$top=10", response.accessToken, callback); }).catch(error => { console.error(error); }); } /** * Helper function to get data from Dataverse * using the authorization bearer token scheme * callback is the writeTable function below */ function getDataverse(url, token, callback) { const headers = new Headers(); const bearer = `Bearer ${token}`; headers.append("Authorization", bearer); // Other Dataverse headers headers.append("Accept", "application/json"); headers.append("OData-MaxVersion", "4.0"); headers.append("OData-Version", "4.0"); const options = { method: "GET", headers: headers }; console.log('GET Request made to Dataverse at: ' + new Date().toString()); fetch(webAPIEndpoint+"/"+url, options) .then(response => response.json()) .then(response => callback(response)) .catch(error => console.log(error)); } // Renders the table with data from GetAccounts function writeTable(data) { data.value.forEach(function (account) { var name = account.name; var city = account.address1_city; var nameCell = document.createElement("td"); nameCell.textContent = name; var cityCell = document.createElement("td"); cityCell.textContent = city; var row = document.createElement("tr"); row.appendChild(nameCell); row.appendChild(cityCell); accountsTableBody.appendChild(row); }); accountsTable.style.display = "block"; getAccountsButton.style.display = "none"; } selectAccount(); </script> </body> </html>
Nota
El código JavaScript de la página HTML se adaptó del código de ejemplo publicado aquí: https://github.com/Azure-Samples/ms-identity-javascript-v2 que se conecta a Microsoft Graph.
La diferencia clave son los ámbitos utilizados al obtener el token de acceso.
Utilice estos ámbitos para el botón de inicio de sesión:
// Called by the loginButton function signIn() { myMSALObj.loginPopup({ scopes: ["User.Read",baseUrl+"/user_impersonation"] //<= Includes Dataverse scope })
Estos ámbitos incluyen el ámbito
User.Read
de Microsoft Graph y también el ámbitouser_impersonation
de Dataverse. Al incluir ambos ámbitos al iniciar sesión, el cuadro de diálogo de consentimiento inicial incluirá todos los ámbitos necesarios utilizados en la aplicación.Luego, al especificar el ámbito utilizado para la llamada a Dataverse puede usar
/.default
o/user_impersonation
.// Retrieves top 10 account records from Dataverse function getAccounts(callback) { // Gets the access token getTokenPopup({ scopes: [baseUrl+"/.default"] })
El ámbito
/user_impersonation
solo funciona para permisos delegados, que es el caso aquí, por lo que podría usarse./.default
funciona tanto para permisos delegados como de aplicación.Si no incluye el ámbito
baseUrl+"/user_impersonation"
al iniciar sesión, el usuario tendrá que dar su consentimiento por segunda vez cuando haga clic en el botón Obtener cuentas por primera vez.Puede encontrar otros ejemplos y tutoriales de SPA aquí: Documentación de solicitud de una sola página (SPA).
Dentro de la página index.html, localice las siguientes variables de configuración y configúrelas utilizando la información que recopiló en los pasos anteriores: Conseguir su punto de conexión de API web de Dataverse y Registrar su aplicación.
const baseUrl = "https://org.api.crm.dynamics.com"; //<= Change this const clientId = "11111111-1111-1111-1111-111111111111"; //<= Change this const tenantId = "22222222-2222-2222-2222-222222222222"; //<= Change this
Depurar la aplicación
Debido a que instaló la extensión Live Server en Instalar la extensión Live Server de Visual Studio Code, en la barra de herramientas de VS Code debería encontrar este botón: .
Haga clic en el botón Poner en marcha y se abrirá una nueva ventana del navegador para
http://localhost:5500/index.html
que representa la página index.html.La primera vez que ejecuta la aplicación y hace clic en el botón Acceso, obtendrá un cuadro de diálogo de consentimiento como este:
Si es administrador, puede seleccionar la casilla Consentimiento en nombre de su organización que permitirá que otros también ejecuten la aplicación sin tener que usar el diálogo Permisos solicitados.
Haga clic en Aceptar para continuar probando para verificar que la aplicación funciona como se describe en Objetivo de este inicio rápido.
Solución de problemas
La experiencia en este inicio rápido depende de que la configuración del puerto de Live Server sea el valor predeterminado:5500
. Si ya tiene Live Server instalado y ha modificado la configuración del puerto, deberá cambiar la configuración predeterminada o la URL establecida en el registro de la aplicación.
Tenga en cuenta que liveServer.settings.port
también se puede establecer para el espacio de trabajo y anulará el ajuste Usuario.
Si abre varias instancias de Live Server, la configuración del puerto puede aumentar a 5501 o superior. Esto romperá la devolución de llamada utilizada para la autenticación porque el puerto está 'codificado' en el registro de la aplicación como http://localhost:5500/index.html
.
Consulte también
Documentación de aplicación de una sola página (SPA)
Usar OAuth con uso compartido de recursos entre orígenes para conectar una aplicación de una sola página a Dataverse
Crear aplicaciones cliente
Nota
¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)
La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).