Crear una API de REST para un evento de inicio de emisión de token en Azure Functions

En este artículo se describe cómo crear una API de REST con un evento de inicio de emisión de tokens mediante Azure Functions en Azure Portal. Cree una aplicación de función de Azure y una función de desencadenador HTTP que pueda devolver notificaciones adicionales para el token.

Requisitos previos

En este artículo se describe cómo crear una API de REST para un evento de inicio de emisión de tokens mediante la biblioteca NuGet Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents y configurarla para la autenticación. Creará una función de desencadenador HTTP en Visual Studio o Visual Studio Code, la configurará para la autenticación y la implementará en Azure Portal, donde se puede acceder a ella a través de Azure Functions.

Requisitos previos

Nota:

La biblioteca NuGet Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents está actualmente en versión preliminar. Los pasos de este artículo están sujetos a cambios. Para la implementación de disponibilidad general de la implementación de un evento de inicio de emisión de token, puede hacerlo mediante Azure Portal.

Creación de la aplicación Azure Function

En Azure Portal, cree una aplicación de función de Azure y su recurso asociado, antes de continuar con la creación de la función desencadenador HTTP.

  1. Inicie sesión en Azure Portal como al menos un Administrador de aplicaciones y un Administrador de autenticación.

  2. En el menú o la página Inicio de Azure Portal, seleccione Crear un recurso.

  3. Busque y seleccione Aplicación de funciones y seleccione Crear.

  4. En la página Aspectos básicos, cree una aplicación de funciones con la configuración especificada en la tabla siguiente:

    Configuración Valor sugerido Descripción
    Suscripción Su suscripción Suscripción donde se creará la nueva aplicación de funciones.
    Grupo de recursos myResourceGroup Seleccione un grupo de recursos actual o proporcione el nombre para uno nuevo donde creará la aplicación de funciones.
    Nombre de la aplicación de función Nombre único globalmente Nombre que identifica la nueva aplicación de funciones. Los caracteres válidos son a-z (no distingue mayúsculas de minúsculas), 0-9 y -.
    Implementación de código o imagen de contenedor Código Opción para publicar archivos de código o un contenedor de Docker. Para este tutorial, seleccione Code.
    Pila en tiempo de ejecución .NET Lenguaje de programación que prefiere. Para este tutorial, seleccione .NET.
    Versión 6 (LTS) en curso Versión del entorno de ejecución de .NET. En curso indica que puede crear y modificar funciones en el portal, algo que se recomienda para esta guía.
    Región Región preferida Seleccione una región próxima a usted o a otros servicios a los que accedan las funciones.
    Sistema operativo Windows El sistema operativo se preselecciona según la selección de la pila en tiempo de ejecución.
    Tipo de plan Consumo (sin servidor) Plan de hospedaje que define cómo se asignan los recursos a la Function App.
  5. Seleccione Revisar y crear para revisar la configuración seleccionada para la aplicación y elija Crear. La implementación tarda unos minutos.

  6. Una vez implementada, seleccione Ir al recurso para ver la nueva aplicación de funciones.

Creación de una función desencadenada por HTTP

Después de crear la aplicación de funciones de Azure, cree una función de desencadenador HTTP dentro de la aplicación. El desencadenador HTTP le permite invocar una función con una solicitud HTTP y la extensión de autenticación personalizada de Microsoft Entra hace referencia a esta.

  1. En la página Información general de la aplicación de funciones, seleccione el panel Funciones y seleccione Crear función en Crear en Azure Portal.
  2. En la ventana Crear función, mantenga la propiedad Entorno de desarrollo como Desarrollo en el portal. En Plantilla, seleccione Desencadenador HTTP.
  3. En Detalles de la plantilla, escriba CustomAuthenticationExtensionsAPI para la propiedad Nueva función.
  4. En Nivel de autorización, seleccione Función.
  5. Seleccione Crear. Captura de pantalla que muestra cómo elegir el entorno de desarrollo y la plantilla.

Edite la función

El código lee el objeto JSON entrante y Microsoft Entra ID envía el objeto JSON a la API. En este ejemplo, lee el valor del id. de correlación. A continuación, el código devuelve una colección de notificaciones personalizadas, incluido el CorrelationId original, la ApiVersion de la función de Azure, DateOfBirth y CustomRoles que se devuelve a Microsoft Entra ID.

  1. En el menú, en Desarrollador, seleccione Código y prueba.

  2. Reemplace todo el código por el siguiente fragmento de código y, a continuación, seleccione Guardar.

    #r "Newtonsoft.Json"
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Newtonsoft.Json;
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
    
        // Read the correlation ID from the Microsoft Entra request    
        string correlationId = data?.data.authenticationContext.correlationId;
    
        // Claims to return to Microsoft Entra
        ResponseContent r = new ResponseContent();
        r.data.actions[0].claims.CorrelationId = correlationId;
        r.data.actions[0].claims.ApiVersion = "1.0.0";
        r.data.actions[0].claims.DateOfBirth = "01/01/2000";
        r.data.actions[0].claims.CustomRoles.Add("Writer");
        r.data.actions[0].claims.CustomRoles.Add("Editor");
        return new OkObjectResult(r);
    }
    public class ResponseContent{
        [JsonProperty("data")]
        public Data data { get; set; }
        public ResponseContent()
        {
            data = new Data();
        }
    }
    public class Data{
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public List<Action> actions { get; set; }
        public Data()
        {
            odatatype = "microsoft.graph.onTokenIssuanceStartResponseData";
            actions = new List<Action>();
            actions.Add(new Action());
        }
    }
    public class Action{
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public Claims claims { get; set; }
        public Action()
        {
            odatatype = "microsoft.graph.tokenIssuanceStart.provideClaimsForToken";
            claims = new Claims();
        }
    }
    public class Claims{
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string CorrelationId { get; set; }
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string DateOfBirth { get; set; }
        public string ApiVersion { get; set; }
        public List<string> CustomRoles { get; set; }
        public Claims()
        {
            CustomRoles = new List<string>();
        }
    }
    
  3. En el menú superior, seleccione Obtener la dirección URL de la función y copie el valor de la dirección URL. Esta dirección URL de función se puede usar al configurar una extensión de autenticación personalizada.

Creación y compilación de la aplicación de Azure Function

En este paso, creará una API de función de desencadenador HTTP mediante el IDE, instalará los paquetes NuGet necesarios y copiará en el código de ejemplo. Compile el proyecto y ejecute la función para extraer la dirección URL de la función local.

Creación de la aplicación

Para crear una aplicación de Azure Function, siga estos pasos:

  1. Abra Visual Studio y seleccione Crear un proyecto.
  2. Busque y seleccione Azure Functions y, a continuación, seleccione Siguiente.
  3. Asigne al proyecto un nombre, como AuthEventsTrigger. Es recomendable que el nombre de la solución coincida con el nombre del proyecto.
  4. Seleccione una ubicación para el proyecto. Seleccione Siguiente.
  5. Seleccione .NET 6.0 (Compatibilidad a largo plazo) como plataforma de destino.
  6. Seleccione Desencadenador Http como tipo de Función y que el nivel de autorización esté establecido en Función. Seleccione Crear.
  7. En el Explorador de soluciones, cambie el nombre del archivo Function1.cs a AuthEventsTrigger.cs y acepte la sugerencia de cambio de nombre.

Instalación de paquetes NuGet y compilación del proyecto

Después de crear el proyecto, deberá instalar los paquetes NuGet necesarios y compilar el proyecto.

  1. En el menú superior de Visual Studio, seleccione Proyecto y, después, Administrar paquetes NuGet.
  2. Seleccione la pestaña Examinar y busque y seleccione Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents en el panel derecho. Seleccione Instalar.
  3. Aplique y acepte los cambios en los elementos emergentes que aparecen.

Incorporación del código de ejemplo

La API de función es el origen de las notificaciones adicionales para el token. Para los fines de este artículo, estamos codificando de forma rígida los valores de la aplicación de ejemplo. En producción, puede capturar información sobre el usuario desde el almacén de datos externo. Consulte la clase WebJobsAuthenticationEventsContext para ver las propiedades existentes.

En el archivo AuthEventsTrigger.cs, reemplace todo el contenido del archivo por el código siguiente:

using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.TokenIssuanceStart;
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;

namespace AuthEventsTrigger
{
    public static class AuthEventsTrigger
    {
        [FunctionName("onTokenIssuanceStart")]
        public static WebJobsAuthenticationEventResponse Run(
            [WebJobsAuthenticationEventsTrigger] WebJobsTokenIssuanceStartRequest request, ILogger log)
        {
            try
            {
                // Checks if the request is successful and did the token validation pass
                if (request.RequestStatus == WebJobsAuthenticationEventsRequestStatusType.Successful)
                {
                    // Fetches information about the user from external data store
                    // Add new claims to the token's response
                    request.Response.Actions.Add(
                        new WebJobsProvideClaimsForToken(
                            new WebJobsAuthenticationEventsTokenClaim("dateOfBirth", "01/01/2000"),
                            new WebJobsAuthenticationEventsTokenClaim("customRoles", "Writer", "Editor"),
                            new WebJobsAuthenticationEventsTokenClaim("apiVersion", "1.0.0"),
                            new WebJobsAuthenticationEventsTokenClaim(
                                "correlationId", 
                                request.Data.AuthenticationContext.CorrelationId.ToString())));
                }
                else
                {
                    // If the request fails, such as in token validation, output the failed request status, 
                    // such as in token validation or response validation.
                    log.LogInformation(request.StatusMessage);
                }
                return request.Completed();
            }
            catch (Exception ex) 
            { 
                return request.Failed(ex);
            }
        }
    }
}

Compilar y ejecutar el proyecto localmente

Se ha creado el proyecto y se ha agregado el código de ejemplo. Con el IDE, es necesario compilar y ejecutar el proyecto localmente para extraer la dirección URL de la función local.

  1. Vaya a Compilar en el menú superior y seleccione Compilar solución.
  2. Presione F5 o seleccione AuthEventsTrigger en el menú superior para ejecutar la función.
  3. Copie la dirección URL de la Función desde el terminal que aparece al ejecutar la función. Esto se puede usar al configurar una extensión de autenticación personalizada.

Es una buena idea probar la función localmente antes de implementarla en Azure. Podemos usar un cuerpo JSON ficticio que imita la solicitud que Microsoft Entra ID envía a la API de REST. Use la herramienta de prueba de API preferida para llamar directamente a la función.

  1. En el IDE, abra local.settings.json y reemplace el código por el siguiente JSON. Podemos establecer "AuthenticationEvents__BypassTokenValidation" en true con fines de prueba locales.

    {
      "IsEncrypted": false,
      "Values": {
        "AzureWebJobsStorage": "",
        "AzureWebJobsSecretStorageType": "files",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "AuthenticationEvents__BypassTokenValidation" : true
      }
    }
    
  2. Con la herramienta de prueba de API preferida, cree una nueva solicitud HTTP y establezca el método HTTP en POST.

  3. Use el siguiente cuerpo JSON que imita la solicitud que Microsoft Entra ID envía a la API de REST.

    {
        "type": "microsoft.graph.authenticationEvent.tokenIssuanceStart",
        "source": "/tenants/aaaabbbb-0000-cccc-1111-dddd2222eeee/applications/00001111-aaaa-2222-bbbb-3333cccc4444",
        "data": {
            "@odata.type": "microsoft.graph.onTokenIssuanceStartCalloutData",
            "tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
            "authenticationEventListenerId": "11112222-bbbb-3333-cccc-4444dddd5555",
            "customAuthenticationExtensionId": "22223333-cccc-4444-dddd-5555eeee6666",
            "authenticationContext": {
                "correlationId": "aaaa0000-bb11-2222-33cc-444444dddddd",
                "client": {
                    "ip": "127.0.0.1",
                    "locale": "en-us",
                    "market": "en-us"
                },
                "protocol": "OAUTH2.0",
                "clientServicePrincipal": {
                    "id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
                    "appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
                    "appDisplayName": "My Test application",
                    "displayName": "My Test application"
                },
                "resourceServicePrincipal": {
                    "id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
                    "appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
                    "appDisplayName": "My Test application",
                    "displayName": "My Test application"
                },
                "user": {
                    "companyName": "Casey Jensen",
                    "createdDateTime": "2023-08-16T00:00:00Z",
                    "displayName": "Casey Jensen",
                    "givenName": "Casey",
                    "id": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
                    "mail": "casey@contoso.com",
                    "onPremisesSamAccountName": "Casey Jensen",
                    "onPremisesSecurityIdentifier": "<Enter Security Identifier>",
                    "onPremisesUserPrincipalName": "Casey Jensen",
                    "preferredLanguage": "en-us",
                    "surname": "Jensen",
                    "userPrincipalName": "casey@contoso.com",
                    "userType": "Member"
                }
            }
        }
    }
    
    
  4. Seleccione Enviar y debería recibir una respuesta JSON similar a la siguiente:

    {
        "data": {
            "@odata.type": "microsoft.graph.onTokenIssuanceStartResponseData",
            "actions": [
                {
                    "@odata.type": "microsoft.graph.tokenIssuanceStart.provideClaimsForToken",
                    "claims": {
                        "customClaim1": "customClaimValue1",
                        "customClaim2": [
                            "customClaimString1",
                            "customClaimString2" 
                        ]
                    }
                }
    
            ]
        }
    }
    

Implementación de la función y publicación en Azure

La función debe implementarse en Azure mediante nuestro IDE. Compruebe que ha iniciado sesión correctamente en su cuenta de Azure para que se pueda publicar la función.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Publicar.

  2. En Destino, seleccione Azure y, a continuación, seleccione Siguiente.

  3. Seleccione Azure Function App (Windows) para Destino específico, seleccione Azure Function App (Windows) y, después, seleccione Siguiente.

  4. En la instancia de Function, use la lista desplegable Nombre de suscripción para seleccionar la suscripción en la que se creará la nueva aplicación de funciones.

  5. Seleccione dónde desea publicar la nueva aplicación de funciones y seleccione Crear nueva.

  6. En la página Aplicación de funciones (Windows), use la configuración de la aplicación de funciones tal como se especifica en la tabla siguiente y, a continuación, seleccione Crear.

    Configuración Valor sugerido Description
    Nombre Nombre único globalmente Nombre que identifica la nueva aplicación de funciones. Los caracteres válidos son a-z (no distingue mayúsculas de minúsculas), 0-9 y -.
    Suscripción Su suscripción Suscripción en la que se creará esta nueva aplicación de función.
    Grupo de recursos myResourceGroup Seleccione un grupo de recursos actual o proporcione el nombre para uno nuevo donde creará la aplicación de funciones.
    Tipo de plan Consumo (sin servidor) Plan de hospedaje que define cómo se asignan los recursos a la Function App.
    Ubicación Región preferida Seleccione una región próxima a usted o a otros servicios a los que accedan las funciones.
    Almacenamiento de Azure Cuenta de almacenamiento El runtime de Functions necesita una cuenta de almacenamiento de Azure. Seleccione Nueva para configurar una cuenta de almacenamiento de uso general.
    Application Insights Valor predeterminado Característica de Azure Monitor. Se selecciona automáticamente, seleccione la que quiera usar o configure una nueva.
  7. Espere unos instantes a que se implemente la aplicación de funciones. Una vez que se cierre la ventana, seleccione Finalizar.

  8. Se abre un nuevo panel Publicar. En la parte superior, seleccione Publicar. Espere unos minutos para que la aplicación de funciones se implemente y se muestre en Azure Portal.

Configurar la autenticación para la función de Azure

Hay tres maneras de configurar la autenticación para la función de Azure:

De forma predeterminada, el código se ha configurado para la autenticación en Azure Portal mediante variables de entorno. Use las pestañas siguientes para seleccionar el método preferido para implementar variables de entorno, o bien, consulte la autenticación y autorización del servicio de Aplicación de Azure integradas. Para configurar variables de entorno, use los siguientes valores:

NOMBRE Valor
AuthenticationEvents__AudienceAppId Id. de aplicación de extensión de autenticación personalizada que se configura en Configurar un proveedor de notificaciones personalizado para un evento de emisión de tokens
AuthenticationEvents__AuthorityUrl • Inquilino de recursos https://login.microsoftonline.com/<tenantID>
• Inquilino externo https://<mydomain>.ciamlogin.com/<tenantID>
AuthenticationEvents__AuthorizedPartyAppId 99045fe1-7639-4a75-9d4a-577b6ca3810f u otra parte autorizada

Configurar la autenticación en Azure Portal mediante variables de entorno

  1. Inicie sesión en Azure Portal como al menos un Administrador de aplicaciones y un Administrador de autenticación.
  2. Vaya a la aplicación de funciones que creó y, en Valores, seleccione Configuración.
  3. En Configuración de la aplicación, seleccione Nueva configuración de aplicación y agregue las variables de entorno de la tabla y sus valores asociados.
  4. Seleccione Guardar para guardar la configuración de la aplicación.

Paso siguiente