Compartir a través de


Protección de las API sin servidor con Azure API Management y Azure AD B2C para su consumo desde una aplicación de página única

SE APLICA A: todos los niveles de API Management

Importante

A partir del 1 de mayo de 2025, Azure AD B2C ya no estará disponible para la compra por parte de nuevos clientes. Obtenga más información en nuestras preguntas más frecuentes.

En este escenario se muestra cómo configurar la instancia de Azure API Management para proteger una API. Usamos el flujo SPA de Azure AD B2C (Código de autenticación + PKCE) para adquirir un token, junto con API Management para proteger un servicio de fondo de Azure Functions mediante EasyAuth.

Para obtener información general conceptual sobre la autorización de API, consulte Autenticación y autorización para API en API Management.

Objetivos

Vamos a ver cómo se puede usar API Management en un escenario simplificado con Azure Functions y Azure AD B2C. Creará una aplicación JavaScript (JS) que llama a una API que inicia la sesión de los usuarios con Azure AD B2C. A continuación, usará las características de directiva de validación de JWT, CORS y limitar la tasa de llamadas por clave de API Management para proteger la API de back-end.

Para la defensa en profundidad, usamos EasyAuth para validar el token de nuevo dentro de la API de back-end y garantizar que API Management es el único servicio que puede llamar al back-end de Azure Functions.

Qué aprenderá

  • Configuración de una aplicación de página única y una API de back-end en Azure Active Directory B2C
  • Creación de una API de back-end Azure Functions
  • Importación de una API de Azure Functions en Azure API Management
  • Protección de la API en Azure API Management
  • Llamada a los puntos de conexión de autorización de Azure Active Directory B2C a través de las bibliotecas de la plataforma de identidad de Microsoft (MSAL.js)
  • Almacenamiento de una aplicación de página única en HTML/Vanilla JS y servirla desde un endpoint de almacenamiento de Azure Blob Storage

Requisitos previos

Para seguir los pasos de este artículo, debe tener:

  • Una cuenta de almacenamiento de Azure (StorageV2) de uso general V2 para hospedar la aplicación de página única JS de front-end.
  • Una instancia de Azure API Management (cualquier nivel funciona, incluido "Consumo"; sin embargo, algunas características aplicables al escenario completo no están disponibles en este nivel, como "rate-limit-by-key" y "dedicated Virtual IP"). Estas restricciones se describen a continuación en el artículo cuando corresponda.
  • Una aplicación de Azure Functions vacía (que ejecute el entorno de ejecución de .NET Core V3.1 en un plan de consumo) para hospedar la API llamada.
  • Un inquilino de Azure AD B2C vinculado a una suscripción.

Aunque en la práctica usarías recursos de la misma región en cargas de trabajo de producción, para este artículo práctico, la región de implementación no es importante.

Información general

A continuación se muestra una ilustración de los componentes en uso y el flujo entre ellos una vez completado este proceso. Componentes en uso y flujo

Aquí se muestra una rápida visión general de los pasos:

  1. Cree las aplicaciones de llamada de Azure AD B2C (front-end, API Management) y de API con ámbitos, y concédales acceso de API

  2. Cree las directivas de registro e inicio de sesión para permitir que los usuarios inicien sesión con Azure AD B2C

  3. Configure API Management con los nuevos identificadores y claves de cliente de Azure AD B2C para habilitar la autorización de usuario de OAuth2 en la consola del desarrollador

  4. Compile Function API

  5. Configure Function API para habilitar Easy Auth con el nuevo identificador y las claves de cliente de Azure AD B2C y realice el bloqueo para la IP virtual de APIM

  6. Compile la definición de API en API Management

  7. Configuración de OAuth2 para la configuración de API Management API

  8. Configure la directivaCORS y agregue la validate-jwt para validar el token de OAuth para todas las solicitudes entrantes

  9. Compile la aplicación que realiza la llamada para que consuma la API

  10. Cargue el ejemplo de aplicación JS de página única

  11. Configure aplicación JS cliente de ejemplo con las nuevas claves y el nuevo identificador de cliente de Azure AD B2C

  12. Pruebe la aplicación cliente

    Sugerencia

    Vamos a capturar bastantes fragmentos de información y claves, etc. al recorrer este documento, es posible que le resulte útil tener un editor de texto abierto para almacenar temporalmente los siguientes elementos de configuración.

    ID. DE CLIENTE DE BACK-END DE B2C: CLAVE DE SECRETO DE CLIENTE DE BACK-END DE B2C: URI DE ÁMBITO DE API DE BACK-END DE B2C: ID. DE CLIENTE DE FRONT-END DE B2C: URI DE PUNTO DE CONEXIÓN DE FLUJO DE USUARIO DE B2C: PUNTO DE CONEXIÓN DE OPENID CONOCIDO DE B2C: NOMBRE DE LA DIRECTIVA DE B2C: Frontendapp_signupandsignin DIRECCIÓN URL DE FUNCIÓN: DIRECCIÓN URL BASE DE APIM API: URL DEL PUNTO DE CONEXIÓN PRINCIPAL DE ALMACENAMIENTO:

Configuración de la aplicación de back-end

Abra la hoja Azure AD B2C en el portal y realice los pasos siguientes.

  1. Seleccione la pestaña Registros de aplicaciones.

  2. Seleccione el botón "Nuevo registro".

  3. Elija "Web" en el cuadro de selección URI de redireccionamiento.

  4. Ahora establezca el Nombre para mostrar, que sea único y pertinente para el servicio que se va a crear. En este ejemplo, usaremos el nombre "Aplicación de back-end".

  5. Use marcadores de posición para las direcciones URL de respuesta, como "https://jwt.ms" (un sitio de descodificación de tokens propiedad de Microsoft), actualizaremos estas direcciones URL más adelante.

  6. Asegúrese de que ha seleccionado la opción "Cuentas en cualquier proveedor de identidades o directorio de la organización (para autenticar usuarios con flujos de usuario)".

  7. En este ejemplo, desactive la casilla "Concesión de consentimiento del administrador", ya que hoy no se requerirán permisos offline_access.

  8. Seleccione "Registrar".

  9. Registre el identificador de cliente de la aplicación de back-end para su uso posterior, que aparece en "Id. de aplicación (cliente)".

  10. Seleccione la pestaña Certificados y secretos (en Administrar) y seleccione "Nuevo secreto de cliente" para generar una clave de autenticación (acepte la configuración predeterminada y seleccione "Agregar").

  11. Al hacer clic en "Agregar", copie la clave (en "valor") en algún lugar seguro para su uso posterior como "Secreto de cliente back-end", tenga en cuenta que este cuadro de diálogo es la única posibilidad de que tenga que copiar esta clave.

  12. Ahora, seleccione la pestaña Exponer una API (en Administrar).

  13. Se le pedirá que establezca el URI de AppID, seleccione y registre el valor predeterminado.

  14. Cree y nombre el ámbito "Hello" para su API de función, puede usar la frase "Hello" para todas las opciones ingresables, registrar el URI del valor completo del ámbito rellenado y luego seleccione "Agregar ámbito".

  15. Vuelva a la raíz de la hoja Azure AD B2C seleccionando la ruta de navegación "Azure AD B2C" en la parte superior izquierda del portal.

    Nota

    Los ámbitos de Azure AD B2C son permisos dentro de la API a los que otras aplicaciones pueden solicitar acceso mediante la hoja de acceso a API de sus aplicaciones.

Configuración de la aplicación de front-end

  1. Seleccione la pestaña Registros de aplicaciones.
  2. Seleccione el botón "Nuevo registro".
  3. Elija "Aplicación de página única (SPA)" en el cuadro de selección del URI de redireccionamiento.
  4. Ahora establezca el nombre para mostrar y el URI de AppID, elija algo único y pertinente para la aplicación de front-end que usará este registro de la aplicación Azure Active Directory B2C. En este ejemplo, puede usar "Aplicación de front-end".
  5. Al igual que en el primer registro de la aplicación, deje la selección de los tipos de cuenta admitidos en su valor predeterminado (autenticación de usuarios con flujos de usuarios).
  6. Use marcadores de posición para las direcciones URL de respuesta, como "https://jwt.ms" (un sitio de descodificación de tokens propiedad de Microsoft), actualizaremos estas direcciones URL más adelante.
  7. Deje marcada la casilla Conceder consentimiento de administrador.
  8. Seleccione "Registrar".
  9. Registre el identificador de cliente de la aplicación de front-end para su uso posterior, que aparece en "Id. de aplicación (cliente)".
  10. Cambie a la pestaña Permisos de API.
  11. Conceda acceso a la aplicación back-end; para ello, haga clic en "Agregar un permiso", seleccione "Mi API", seleccione "Aplicación de back-end", seleccione "Permisos", seleccione el ámbito que creó en la sección anterior y seleccione "Agregar permisos".
  12. Seleccione "Conceder consentimiento del administrador para {tenant} y seleccione "Sí" en el cuadro de diálogo emergente. Este elemento emergente da su consentimiento a la "Aplicación de front-end" para usar el permiso "Hello" definido en la "Aplicación de back-end" que se creó anteriormente.
  13. Todos los permisos deben mostrarse ahora para la aplicación como una marca de verificación verde en la columna de estado.

Creación de un flujo de usuario de "registro e inicio de sesión"

  1. Vuelva a la raíz de la hoja de B2C seleccionando la ruta de navegación de Azure AD B2C.

  2. Cambie a la pestaña "Flujos de usuario" (en Directivas).

  3. Seleccione "Nuevo flujo de usuario"

  4. Elija el tipo de flujo de usuario "Registrarse e iniciar sesión", seleccione "Recomendado" y luego haga clic en "Crear".

  5. Asígnele un nombre a la directiva y regístrelo para más adelante. En este ejemplo, puede usar "Frontendapp_signupandsignin"; tenga en cuenta que se le añadirá el prefijo "B2C_1_" para formar "B2C_1_Frontendapp_signupandsignin".

  6. En "Proveedores de identidades" y "Cuentas locales", compruebe "Registro de correo electrónico" (o "Registro de id. de usuario" en función de la configuración del inquilino de B2C) y seleccione Aceptar. Esta configuración se debe a que vamos a registrar cuentas locales B2C, no remitirnos a otro proveedor de identidades (como un proveedor de identidades sociales) para utilizar la cuenta de redes sociales existente de un usuario.

  7. Deje la configuración de MFA y de acceso condicional en sus valores predeterminados.

  8. En "Atributos de usuario y reclamaciones", seleccione "Mostrar más...". A continuación, elija las opciones de reclamación que desea que los usuarios introduzcan y se devuelvan en el token. Active al menos "Nombre para mostrar" y "Dirección de correo electrónico" para recopilar, con "Nombre para mostrar" y "Direcciones de correo electrónico" para devolver (preste mucha atención al hecho de va a recopilar una dirección de correo electrónico, en singular, y a solicitar que se devuelvan direcciones de correo electrónico, en plural), y haga clic en "Aceptar", y luego en "Crear".

  9. Seleccione el flujo de usuario que creó en la lista y, a continuación, seleccione el botón "Ejecutar flujo de usuario".

  10. Esta acción abre el panel para ejecutar el flujo de usuario, selecciona la aplicación de front-end, copia el punto de conexión del flujo de usuario y lo guarda para más adelante.

  11. Copie y guarde el vínculo de la parte superior, registrándolo como "punto de conexión de configuración de OpenID conocido" para su uso posterior.

    Nota

    Las directivas de B2C permiten exponer los puntos de conexión de inicio de sesión de Azure AD B2C para poder capturar diferentes componentes de datos e iniciar la sesión de los usuarios de diferentes maneras.

    En este caso, se ha configurado un flujo de inicio de registro o de inicio de sesión (directiva). Esto también expuso un punto conexión de configuración conocido, en ambos casos nuestra directiva creada se identificó en la dirección URL mediante el parámetro de cadena de consulta "p=".

    Una vez hecho esto tendrá una plataforma de identidad de negocio a consumidor (B2C) funcional para que los usuarios inicien sesión en varias aplicaciones.

Compilación de la API de función

  1. Vuelva a cambiar al inquilino de Microsoft Entra estándar en Azure Portal para poder configurar de nuevo los elementos de la suscripción.

  2. Vaya a la hoja Aplicaciones de funciones de Azure Portal, abra la aplicación de funciones vacía y seleccione "Functions", seleccione "Agregar".

  3. En el control flotante que aparece, elija "Desarrollar en el portal", bajo "seleccionar una plantilla", elija "Desencadenador HTTP", bajo Detalles de la plantilla, asígnele el nombre "hello" con el nivel de autorización "Función" y seleccione Agregar.

  4. Cambie a la hoja Código y prueba y copie y pegue el código de ejemplo siguiente sobre el código existente que aparece.

  5. Seleccione Guardar.

    
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
       log.LogInformation("C# HTTP trigger function processed a request.");
    
       return (ActionResult)new OkObjectResult($"Hello World, time and date are {DateTime.Now.ToString()}");
    }
    
    

    Sugerencia

    El código de la función de script de C# que acaba de pegar simplemente registra una línea en los registros de función y devuelve el texto "Hola mundo" con algunos datos dinámicos (fecha y hora).

  6. Seleccione "Integración" en el panel izquierdo y, a continuación, seleccione el enlace http (req) dentro del cuadro 'Trigger'.

  7. En la lista desplegable "Métodos HTTP seleccionados", desactive el método HTTP POST, dejando solo GET seleccionado y, a continuación, seleccione Guardar.

  8. Vuelva a la pestaña Código y prueba, seleccione "Obtener dirección URL de la función" y, a continuación, copie la dirección URL que aparece y guárdela para más adelante.

    Nota

    Los enlaces que acaba de crear simplemente indican a las funciones que respondan a solicitudes HTTP GET anónimas a la dirección URL que acaba de copiar (https://yourfunctionappname.azurewebsites.net/api/hello?code=secretkey). Ahora tenemos una API https sin servidor escalable que es capaz de devolver una carga sencilla.

    Ahora puede probar a llamar a esta API desde un explorador web utilizando su versión de la dirección URL anterior que acaba de copiar y guardar. También puede quitar los parámetros de cadena de consulta "?code=secretkey" de la dirección URL y volver a probarlo para demostrar que Azure Functions devolverá un error 401.

Configuración y protección de la API de función

  1. Es necesario configurar dos áreas adicionales en la aplicación de funciones (restricciones de autenticación y de red).

  2. En primer lugar, vamos a configurar la autenticación y la autorización, así que vuelva a la hoja raíz de la aplicación de funciones a través de la ruta de navegación.

  3. Después, seleccione "Autenticación" (en "Configuración").

  4. Seleccione "Agregar proveedor de identidades".

  5. En la lista desplegable del proveedor de identidades, seleccione "Microsoft"

  6. En Registro de aplicaciones, seleccione "Proporcionar los detalles de un registro de aplicaciones existente"

  7. Pegue el Id. de cliente de la aplicación back-end (de Azure AD B2C) en el cuadro "Id. de aplicación (cliente)" (registramos esta configuración anteriormente).

  8. Pegue el punto de conexión de configuración OpenID conocido de la directiva de registro y inicio de sesión en el cuadro URL del emisor (hemos registrado esta configuración anteriormente).

  9. Pegue el secreto de cliente de la aplicación back-end en el cuadro adecuado (registramos esta configuración anteriormente).

  10. En "Solicitudes no autenticadas", seleccione "HTTP 401 No autorizado: recomendado para las API"

  11. Deje habilitado el Almacén de tokens (opción predeterminada).

  12. Seleccione "Guardar" (en la parte superior del panel).

    Importante

    Ahora, la API de Function está implementada, por lo que debe generar respuestas 401 si no se proporciona el JWT correcto como encabezado Autorización: Portador, y también debe devolver datos cuando se presente una solicitud correcta. Ha agregado una medida de seguridad de defensa en profundidad adicional en EasyAuth configurando la opción "Inicio de sesión con Microsoft Entra ID" para administrar las solicitudes no autenticadas.

    Sin embargo, aún no hemos aplicado la seguridad IP. Si tiene una clave válida y un token de OAuth2, cualquiera puede realizar la llamada desde cualquier lugar (lo ideal sería exigir que todas las solicitudes lleguen a través de API Management).

    Si usa los niveles Consumo de API Management, Versión básica v2, Estándar v2 y Premium v2, no hay una dirección IP virtual de Azure API Management dedicada para permitir la lista con las restricciones de acceso a las funciones. En los niveles clásicos (dedicados) de Azure API Management VIP es de inquilino único y para la duración del recurso. Para los niveles que se ejecutan en la infraestructura compartida, puede bloquear las llamadas API a través de la clave de función secreta compartida en la parte del URI que copió anteriormente. Además, para estos niveles: los pasos 12-17 siguientes no se aplican.

  13. Cierre la hoja "Autenticación" desde el portal de App Service o de Functions.

  14. Abra la hoja API Management del portal y, luego, abra su instancia.

  15. Registre la IP virtual privada que aparece en la pestaña Información general.

  16. Vuelva a la hoja Azure Functions del portal y, a continuación, vuelva a abrir su instancia.

  17. Seleccione "Redes" y luego "Configuración de las restricciones de acceso".

  18. Seleccione 'Agregar regla' y escriba el VIP copiado en el paso 3 en el formato xx.xx.xx.xx/32.

  19. Si desea seguir interactuando con el portal de funciones y llevar a cabo los pasos opcionales que se indican a continuación, primero debe agregar su propia dirección IP pública o intervalo CIDR.

  20. Cuando haya una entrada de permiso en la lista, Azure agrega una regla de denegación implícita para bloquear todas las demás direcciones.

Debe agregar bloques con formato CIDR de direcciones al panel de restricciones de IP. Cuando necesite agregar una sola dirección, como la IP virtual de API Management, debe hacerlo en formato xx.xx.xx.xx/32.

Nota

Ahora la API de función no debería poderse llamar desde otro origen distinto mediante API Management o la dirección.

  1. Abra la hoja API Management y después la instancia.

  2. Seleccione la hoja API (en API).

  3. En el panel "Add a New API" (Agregar una nueva API), elija "Function App" y seleccione "Completo" en la parte superior de la ventana emergente.

  4. Haga clic en Examinar, elija la aplicación de funciones que hospede la API y haga clic en Seleccionar. A continuación, haga clic en Seleccionar de nuevo.

  5. Proporciónele un nombre a la API y una descripción para uso interno de API Management y agréguelos al producto "Unlimited" (Ilimitado).

  6. Copie y registre la "dirección URL base" de la API y seleccione "crear".

  7. Seleccione la pestaña "configuración" y, a continuación, en suscripción, desactive la casilla "Suscripción requerida", ya que usaremos el JWT de OAuth en este caso para limitar la velocidad. Tenga en cuenta que, si usa el nivel Consumo, esto seguirá siendo necesario en un entorno de producción.

    Sugerencia

    Si usa el nivel Consumo de APIM, el producto ilimitado no estará disponible de forma inmediata. En su lugar, vaya a "Productos" en "API" y presione "Agregar". Escriba "Unlimited" como nombre y descripción del producto y seleccione la API que acaba de agregar en la llamada api "+" en la parte inferior izquierda de la pantalla. Seleccione la pestaña "Publicadas". Deje el resto tal como está. Por último, pulse el botón "Crear". Esto creó el producto "ilimitado" y lo asignó a su API. Puede personalizar el nuevo producto más adelante.

Configuración y captura de la configuración correcta del punto de conexión de almacenamiento

  1. Abra la hoja Cuentas de almacenamiento en Azure Portal.

  2. Seleccione la cuenta que ha creado y la hoja "Sitio web estático" en la sección Configuración (si no ve la opción "Sitio web estático", compruebe que creó una cuenta V2).

  3. Establezca la característica de hospedaje web estática en "habilitado" y establezca el nombre del documento de índice en "index.html" y, a continuación, seleccione "guardar".

  4. Anote el contenido del punto de conexión principal para más adelante, ya que esta ubicación es donde se hospedará el sitio de front-end.

    Sugerencia

    Puede usar Azure Blob Storage + reescritura de la red CDN, o Azure App Service para hospedar la aplicación de página única, pero la característica de hospedaje de sitios web estáticos de Blob Storage proporciona un contenedor predeterminado que sirve contenido/html/JS/css web estático de Azure Storage e infiere una página predeterminada para que no tengamos que hacer nada.

Configuración de las directivas CORS y validate-jwt

Se deben seguir las siguientes secciones independientemente del nivel de APIM que se use. La dirección URL de la cuenta de almacenamiento es de la cuenta de almacenamiento que estará disponible a raíz de los requisitos previos de la parte superior de este artículo.

  1. Cambie a la hoja API Management del portal y abra su instancia.

  2. Seleccione API y, a continuación, seleccione "Todas las API".

  3. En "Procesamiento de entrada", seleccione el botón de vista de código "</>" para mostrar el editor de directivas.

  4. Edite la sección de entrada y pegue el código XML siguiente para que sea similar al siguiente.

  5. Sustituya los siguientes parámetros en la directiva.

  6. {PrimaryStorageEndpoint} (El punto de conexión de almacenamiento principal que copió en la sección anterior), {b2cpolicy-Well-Known-OpenID} (el "punto de conexión de configuración de OpenID conocido" que copió anteriormente) y {backend-API-Application-Client-ID} (el identificador de cliente/aplicación B2C para la API de back-end) con los valores correctos guardados anteriormente.

  7. Si usa el nivel Consumo de API Management, debe quitar ambas directivas de limitar la tasa de llamadas por clave, ya que esta directiva no está disponible cuando se usa el nivel Consumo de Azure API Management.

    <inbound>
       <cors allow-credentials="true">
             <allowed-origins>
                 <origin>{PrimaryStorageEndpoint}</origin>
             </allowed-origins>
             <allowed-methods preflight-result-max-age="120">
                 <method>GET</method>
             </allowed-methods>
             <allowed-headers>
                 <header>*</header>
             </allowed-headers>
             <expose-headers>
                 <header>*</header>
             </expose-headers>
         </cors>
       <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid." require-expiration-time="true" require-signed-tokens="true" clock-skew="300">
          <openid-config url="{b2cpolicy-well-known-openid}" />
          <required-claims>
             <claim name="aud">
                <value>{backend-api-application-client-id}</value>
             </claim>
          </required-claims>
       </validate-jwt>
       <rate-limit-by-key calls="300" renewal-period="120" counter-key="@(context.Request.IpAddress)" />
       <rate-limit-by-key calls="15" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" />
    </inbound>
    

    Nota

    Ahora, Azure API Management puede responder a las solicitudes entre orígenes desde las aplicaciones de página única de JavaScript y realizará la limitación, la limitación de velocidad y la validación previa del token de autenticación JWT que se pasa ANTES de reenviar la solicitud a la API de función.

    Enhorabuena, ahora tiene Azure AD B2C, API Management y Azure Functions trabajando juntos para publicar, proteger Y consumir una API.

    Sugerencia

    Si usa el nivel Consumo de API Management, en lugar de la limitación de velocidad por el sujeto de JWT o la dirección IP entrante (actualmente no se admite la directiva de limitar la tasa de llamadas por clave para el nivel "Consumo"), puede limitar por la cuota de tasa de llamadas, (consulte aquí). Como este ejemplo es una aplicación JavaScript de página única, la clave de API Management solo se usa para las llamadas de facturación y de limitación de velocidad. La autenticación y la autorización reales se administran mediante Azure AD B2C y se encapsulan en JWT, que se valida dos veces, una desde API Management y, a continuación, desde la función de Azure de backend.

Carga del ejemplo de aplicación de página única de JavaScript en el almacenamiento estático

  1. Todavía en el panel de la cuenta de almacenamiento, seleccione el panel "Contenedores" en la sección Blob Service y luego el contenedor $web que aparece en el panel derecho.

  2. Guarde el código siguiente en un archivo de la máquina como index.html y cargue este archivo en el contenedor $web.

     <!doctype html>
     <html lang="en">
     <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
          <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.11.1/js/msal-browser.min.js"></script>
     </head>
     <body>
          <div class="container-fluid">
              <div class="row">
                  <div class="col-md-12">
                     <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
                         <div class="container-fluid">
                             <a class="navbar-brand" href="#">Azure Active Directory B2C with Azure API Management</a>
                             <div class="navbar-nav">
                                 <button class="btn btn-success" id="signinbtn"  onClick="login()">Sign In</a>
                             </div>
                         </div>
                     </nav>
                  </div>
              </div>
              <div class="row">
                  <div class="col-md-12">
                      <div class="card" >
                         <div id="cardheader" class="card-header">
                             <div class="card-text"id="message">Please sign in to continue</div>
                         </div>
                         <div class="card-body">
                             <button class="btn btn-warning" id="callapibtn" onClick="getAPIData()">Call API</a>
                             <div id="progress" class="spinner-border" role="status">
                                 <span class="visually-hidden">Loading...</span>
                             </div>
                         </div>
                      </div>
                  </div>
              </div>
          </div>
          <script lang="javascript">
                 // Just change the values in this config object ONLY.
                 var config = {
                     msal: {
                         auth: {
                             clientId: "{CLIENTID}", // This is the client ID of your FRONTEND application that you registered with the SPA type in Azure Active Directory B2C
                             authority:  "{YOURAUTHORITYB2C}", // Formatted as https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantguid or full tenant name including onmicrosoft.com}/{signuporinpolicyname}
                             redirectUri: "{StoragePrimaryEndpoint}", // The storage hosting address of the SPA, a web-enabled v2 storage account - recorded earlier as the Primary Endpoint.
                             knownAuthorities: ["{B2CTENANTDOMAIN}"] // {b2ctenantname}.b2clogin.com
                         },
                         cache: {
                             cacheLocation: "sessionStorage",
                             storeAuthStateInCookie: false
                         }
                     },
                     api: {
                         scopes: ["{BACKENDAPISCOPE}"], // The scope that we request for the API from B2C, this should be the backend API scope, with the full URI.
                         backend: "{APIBASEURL}/hello" // The location that we'll call for the backend api, this should be hosted in API Management, suffixed with the name of the API operation (in the sample this is '/hello').
                     }
                 }
                 document.getElementById("callapibtn").hidden = true;
                 document.getElementById("progress").hidden = true;
                 const myMSALObj = new msal.PublicClientApplication(config.msal);
                 myMSALObj.handleRedirectPromise().then((tokenResponse) => {
                     if(tokenResponse !== null){
                         console.log(tokenResponse.account);
                         document.getElementById("message").innerHTML = "Welcome, " + tokenResponse.account.name;
                         document.getElementById("signinbtn").hidden = true;
                         document.getElementById("callapibtn").hidden = false;
                     }}).catch((error) => {console.log("Error Signing in:" + error);
                 });
                 function login() {
                     try {
                         myMSALObj.loginRedirect({scopes: config.api.scopes});
                     } catch (err) {console.log(err);}
                 }
                 function getAPIData() {
                     document.getElementById("progress").hidden = false;
                     document.getElementById("message").innerHTML = "Calling backend ... "
                     document.getElementById("cardheader").classList.remove('bg-success','bg-warning','bg-danger');
                     myMSALObj.acquireTokenSilent({scopes: config.api.scopes, account: getAccount()}).then(tokenResponse => {
                         const headers = new Headers();
                         headers.append("Authorization", `Bearer ${tokenResponse.accessToken}`);
                         fetch(config.api.backend, {method: "GET", headers: headers})
                             .then(async (response)  => {
                                 if (!response.ok)
                                 {
                                     document.getElementById("message").innerHTML = "Error: " + response.status + " " + JSON.parse(await response.text()).message;
                                     document.getElementById("cardheader").classList.add('bg-warning');
                                 }
                                 else
                                 {
                                     document.getElementById("cardheader").classList.add('bg-success');
                                     document.getElementById("message").innerHTML = await response.text();
                                 }
                                 }).catch(async (error) => {
                                     document.getElementById("cardheader").classList.add('bg-danger');
                                     document.getElementById("message").innerHTML = "Error: " + error;
                                 });
                     }).catch(error => {console.log("Error Acquiring Token Silently: " + error);
                         return myMSALObj.acquireTokenRedirect({scopes: config.api.scopes, forceRefresh: false})
                     });
                     document.getElementById("progress").hidden = true;
              }
             function getAccount() {
                 var accounts = myMSALObj.getAllAccounts();
                 if (!accounts || accounts.length === 0) {
                     return null;
                 } else {
                     return accounts[0];
                 }
             }
         </script>
      </body>
     </html>
    
  3. Vaya al punto de conexión principal del sitio web estático que almacenó en la última sección.

    Nota

    Enhorabuena, acaba de implementar una aplicación de página única de JavaScript para el hospedaje de contenido estático de Azure Storage. Dado que no hemos configurado la aplicación JS con los detalles de Azure AD B2C aún, la página no funcionará todavía si la abre.

Configuración de la aplicación de página única de JavaScript SPA para Azure AD B2C

  1. Ahora sabemos dónde está todo: podemos configurar la aplicación de página única con la dirección de API de API Management adecuada y los identificadores de aplicación y de cliente de Azure AD B2C correctos.
  2. Vuelva a la hoja de almacenamiento de Azure Portal.
  3. Seleccione "Contenedores" (en "Configuración").
  4. Seleccione el contenedor "$web" en la lista.
  5. Seleccione el blob index.html en la lista.
  6. Seleccione 'Editar'
  7. Actualice los valores de autenticación en la sección de configuración de MSAL para que coincida con la aplicación de front-end que registró anteriormente en B2C. Use los comentarios de código para ver sugerencias sobre el aspecto que deberían tener los valores de configuración. El valor de autoridad debe tener el formato https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantname}.onmicrosoft.com}/{signupandsigninpolicyname}.Si ha usado los nombres de ejemplo y el inquilino de B2C se llama "contoso", se espera que la autoridad sea "https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/Frontendapp_signupandsignin".
  8. Establezca los valores de la API para que coincidan con la dirección del back-end (la URL base de API que ha registrado antes, y los valores de "b2cScopes" que se han ha registrado para la aplicación de back-end).
  9. Seleccione Guardar.

Establecimiento de los URI de redireccionamiento para la aplicación de front-end de Azure AD B2C

  1. Abra la hoja Azure AD B2C y vaya al registro de la aplicación JavaScript de front-end.

  2. Seleccione "URI de redirección" y elimine el marcador de posición "https://jwt.ms" que especificó anteriormente.

  3. Agregue un nuevo URI para el punto de conexión principal (almacenamiento) (sin la barra diagonal final).

    Nota

    Esta configuración hará que un cliente de la aplicación de front-end reciba un token de acceso con las notificaciones adecuadas de Azure AD B2C. La aplicación de página única podrá agregarlo como token de portador al encabezado HTTPS en la llamada a la API de back-end.

    API Management validará previamente el token, limitará la frecuencia de las llamadas al punto de conexión por el sujeto del JWT emitido por el identificador de Azure (el usuario) y por la dirección IP del autor de la llamada (en función del nivel de servicio de API Management, consulte la nota anterior) antes de pasar la solicitud a la API de Azure Functions de recepción, agregando la clave de seguridad. La aplicación de página única representará la respuesta en el explorador.

    Enhorabuena, ha configurado Azure AD B2C, Azure API Management, Azure Functions y la autorización de Azure App Service para que trabajen en perfecta armonía.

Ahora tenemos una aplicación sencilla con una API segura sencilla, vamos a probarla.

Prueba de la aplicación cliente

  1. Abra la dirección URL de la aplicación de ejemplo que anotó de la cuenta de almacenamiento que creó anteriormente.
  2. Seleccione "Iniciar sesión" en la esquina superior derecha, esta acción abrirá el perfil de registro o de inicio de sesión de Azure AD B2C.
  3. La aplicación debería darte la bienvenida por su nombre de perfil B2C.
  4. Ahora seleccione "Call API" (Llamar a API) y la página debe actualizarse con los valores devueltos desde la API protegida.
  5. Si selecciona repetidamente el botón Call API (Llamar a la API) y se ejecuta en el nivel de desarrollador o superior de API Management, debe tener en cuenta que la solución comenzará a limitar la velocidad de la API y esta característica se debe notificar en la aplicación con un mensaje adecuado.

Y hemos terminado

Los pasos anteriores se pueden adaptar y editar para permitir gran cantidad de usos diferentes de Azure AD B2C con API Management.