Tutorial: autenticación de Azure SignalR Service con Azure Functions

En este tutorial paso a paso, va a crear un salón de chat con autenticación y mensajería privada mediante estas tecnologías:

  • Azure Functions: API de back-end para autenticar a los usuarios y enviar mensajes de chat
  • Azure SignalR Service: servicio para la difusión de nuevos mensajes a los clientes de chat conectados
  • Azure Storage: servicio de almacenamiento que requiere Azure Functions
  • Azure App Service: servicio que proporciona autenticación de usuario

Nota:

Puede obtener el código mencionado en este artículo desde GitHub.

Requisitos previos

¿Tiene problemas? Cuéntenoslo.

Crear recursos esenciales en Azure

Creación de un recurso de Azure SignalR Service

La aplicación accederá a una instancia de Azure SignalR Service. Siga estos pasos para crear una instancia de Azure SignalR Service mediante Azure Portal.

  1. En Azure Portal, seleccione el botón Crear un recurso (+).

  2. Busque SignalR Service y selecciónelo.

  3. Seleccione Crear.

  4. Escriba la siguiente información.

    Nombre Value
    Grupo de recursos Cree un grupo de recursos y asígnele con un nombre único
    Nombre del recurso Escriba un nombre único para la instancia de Azure SignalR Service.
    Región Seleccione una región cercana.
    Plan de tarifa Seleccione Gratis.
    Modo de servicio Seleccione Sin servidor.
  5. Seleccione Revisar + crear.

  6. Seleccione Crear.

¿Tiene problemas? Cuéntenoslo.

Creación de una aplicación de funciones de Azure y una cuenta de almacenamiento de Azure

  1. En la página principal de Azure Portal, seleccione Crear un recurso (+).

  2. Busque la opción Aplicación de funciones y selecciónela.

  3. Seleccione Crear.

  4. Escriba la siguiente información.

    Nombre Value
    Grupo de recursos Use el mismo grupo de recursos con la instancia de Azure SignalR Service.
    Nombre de la aplicación de función Escriba un nombre único para la aplicación de funciones.
    Pila del entorno en tiempo de ejecución seleccione Node.js.
    Región Seleccione una región cercana.
  5. De forma predeterminada, también se crea una nueva cuenta de almacenamiento de Azure en el mismo grupo de recursos junto con la aplicación de funciones. Si quiere usar otra cuenta de almacenamiento en la aplicación de funciones, cambie a la pestaña Hospedaje para elegir una cuenta.

  6. Seleccione Revisar y crear y, luego, Crear.

Crear un proyecto de Azure Functions localmente

Inicializar una aplicación de funciones

  1. Desde una línea de comandos, cree una carpeta raíz para el proyecto y cambie a dicha carpeta.

  2. Ejecute el comando siguiente en el terminal para crear un proyecto de funciones de JavaScript.

func init --worker-runtime node --language javascript --name my-app --model V4

De forma predeterminada, el proyecto generado incluye un archivo host.json que contiene los conjuntos de extensiones que incluyen la extensión SignalR. Para obtener más información sobre las agrupaciones de extensiones, consulte Registro de las extensiones de enlace de Azure Functions.

Configuración de la aplicación

Al ejecutar y depurar el entorno de ejecución de Azure Functions localmente, la aplicación de funciones lee la configuración de la aplicación desde local.settings.json. Actualice este archivo con la cadena de conexión de la instancia de Azure SignalR Service y la cuenta de almacenamiento que ha creado anteriormente.

Reemplace el contenido del archivo local.settings.json por el código siguiente:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsStorage": "<your-storage-account-connection-string>",
    "AzureSignalRConnectionString": "<your-Azure-SignalR-connection-string>"
  }
}

En el código anterior:

  • Escriba la cadena de conexión de Azure SignalR Service en el valor AzureSignalRConnectionString.

    Para obtener la cadena, vaya a la instancia de Azure SignalR Service en Azure Portal. En la sección Configuración, busque el valor Claves. Seleccione el botón Copiar situado a la derecha de la cadena de conexión para copiarla en el Portapapeles. Puede usar la cadena de conexión principal o la secundaria.

  • Escriba la cadena de conexión de la cuenta de almacenamiento en el valor AzureWebJobsStorage.

    Para obtener la cadena, vaya a la cuenta de almacenamiento en Azure Portal. En la sección Seguridad y redes, busque el valor Claves de acceso. Seleccione el botón Copiar situado a la derecha de la cadena de conexión para copiarla en el Portapapeles. Puede usar la cadena de conexión principal o la secundaria.

¿Tiene problemas? Háganoslo saber.

Creación de una función para autenticar usuarios en Azure SignalR Service

Cuando se abre la aplicación de chat por primera vez en el explorador, este requiere unas credenciales de conexión válidas para conectarse a Azure SignalR Service. Va a crear una función de desencadenador HTTP denominada negotiate en la aplicación de funciones para devolver esta información de conexión.

Nota:

Esta función debe denominarse negotiate, ya que el cliente de SignalR requiere un punto de conexión que termine en /negotiate.

  1. En la carpeta raíz del proyecto, cree la función negotiate a partir de una plantilla integrada mediante el comando siguiente.

    func new --template "HTTP trigger" --name negotiate
    
  2. Abra src/functions/negotiate.js, actualice el contenido de la siguiente manera:

    const { app, input } = require('@azure/functions');
    
    const inputSignalR = input.generic({
        type: 'signalRConnectionInfo',
        name: 'connectionInfo',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
    });
    
    app.post('negotiate', {
        authLevel: 'anonymous',
        handler: (request, context) => {
            return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) }
        },
        route: 'negotiate',
        extraInputs: [inputSignalR],
    });
    

    La función contiene un enlace de desencadenador HTTP para recibir solicitudes de clientes de SignalR. La función también contiene un enlace de entrada que genera credenciales válidas para que un cliente se conecte a un centro de conectividad de Azure SignalR Service denominado default.

    Esta función toma la información de conexión de SignalR del enlace de entrada y la devuelve al cliente en el cuerpo de la respuesta HTTP.

    No hay ninguna propiedad userId en el enlace signalRConnectionInfo para el desarrollo local. Lo agregará más adelante para establecer el nombre de usuario de una conexión de SignalR al implementar la aplicación de funciones en Azure.

¿Tiene problemas? Cuéntenoslo.

Creación de una función para enviar mensajes de chat

La aplicación web también necesita una API de HTTP para enviar mensajes de chat. Cree una función de desencadenador HTTP que envíe mensajes a todos los clientes conectados mediante Azure SignalR Service.

  1. En la carpeta del proyecto raíz, cree una función de desencadenador HTTP denominada sendMessage a partir de la plantilla mediante el comando siguiente:

    func new --name sendMessage --template "Http trigger"
    
  2. Abra el archivo src/functions/sendMessage.js y actualice el contenido de la siguiente manera:

    const { app, output } = require('@azure/functions');
    
    const signalR = output.generic({
        type: 'signalR',
        name: 'signalR',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
    });
    
    app.http('messages', {
        methods: ['POST'],
        authLevel: 'anonymous',
        extraOutputs: [signalR],
        handler: async (request, context) => {
            const message = await request.json();
            message.sender = request.headers && request.headers.get('x-ms-client-principal-name') || '';
    
            let recipientUserId = '';
            if (message.recipient) {
                recipientUserId = message.recipient;
                message.isPrivate = true;
            }
            context.extraOutputs.set(signalR,
                {
                    'userId': recipientUserId,
                    'target': 'newMessage',
                    'arguments': [message]
                });
        }
    });
    

    La función contiene un desencadenador HTTP y un enlace de salida de SignalR. Coge el cuerpo de la solicitud HTTP y lo envía a los clientes conectados al servicio Azure SignalR. Invoca una función denominada newMessage en cada cliente.

    La función puede leer la identidad del emisor y puede aceptar un valor de recipient en el cuerpo del mensaje para permitirle que envíe un mensaje de forma privada a un solo usuario. Más adelante en el tutorial usará estas funcionalidades.

  3. Guarde el archivo.

¿Tiene problemas? Háganoslo saber.

Hospedaje de la interfaz de usuario web del cliente de chat

La interfaz de usuario de la aplicación de chat es una aplicación de página única (SPA) que se crea con el marco Vue JavaScript mediante el cliente de JavaScript en ASP.NET Core SignalR. Para simplificar, la aplicación de funciones hospeda la página web. En un entorno de producción, puede usar Static Web Apps para hospedar la página web.

  1. Cree un archivo denominado index.html en el directorio raíz del proyecto de función.

  2. Copie y peque el contenido de index.html en el archivo. Guarde el archivo.

  3. En la carpeta del proyecto raíz, cree una función de desencadenador HTTP denominada index a partir de la plantilla mediante este comando:

    func new --name index --template "Http trigger"
    
  4. Modifique el contenido de src/functions/index.js en el código siguiente:

    const { app } = require('@azure/functions');
    const { readFile } = require('fs/promises');
    
    app.http('index', {
        methods: ['GET'],
        authLevel: 'anonymous',
        handler: async (context) => {
            const content = await readFile('index.html', 'utf8', (err, data) => {
                if (err) {
                    context.err(err)
                    return
                }
            });
    
            return {
                status: 200,
                headers: {
                    'Content-Type': 'text/html'
                },
                body: content,
            };
        }
    });
    

    La función lee la página web estática y la devuelve al usuario.

  5. Pruebe localmente la aplicación. Inicie la aplicación de funciones con este comando:

    func start
    
  6. Abra http://localhost:7071/api/index en el explorador web. Debería aparecer una página web de chat.

    Captura de pantalla de una interfaz de usuario web para un cliente de chat local.

  7. Escriba un mensaje en el cuadro de chat.

    Después de seleccionar la tecla Entrar, el mensaje aparece en la página web. Dado que no se ha establecido el nombre de usuario del cliente de SignalR, se envían todos los mensajes de forma anónima.

¿Tiene problemas? Cuéntenoslo.

Implementación en Azure y habilitación de la autenticación

Hasta ahora, ha ejecutado la aplicación de funciones y la de chat de forma local. Ahora las implementará en Azure y habilitará la autenticación y la mensajería privada.

Configuración de una aplicación de funciones para la autenticación

Hasta ahora, la aplicación de chat funciona de forma anónima. En Azure, deberá utilizar la autenticación de App Service para autenticar al usuario. El identificador o el nombre de usuario del usuario autenticado se pasa al enlace SignalRConnectionInfo para generar información de conexión que se autentica como el usuario.

  1. Abra el archivo src/functions/negotiate.js.

  2. Inserte una propiedad userId en el enlace inputSignalR con el valor {headers.x-ms-client-principal-name}. Este valor es una expresión de enlace que establece el nombre de usuario del cliente de SignalR en el nombre del usuario autenticado. El enlace debería tener ahora un aspecto similar al de este ejemplo:

    const inputSignalR = input.generic({
        type: 'signalRConnectionInfo',
        name: 'connectionInfo',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
        userId: '{headers.x-ms-client-principal-name}'
    });
    
  3. Guarde el archivo.

Implementación de la aplicación de funciones en Azure

Implemente la aplicación de funciones en Azure mediante el comando siguiente:

func azure functionapp publish <your-function-app-name> --publish-local-settings

La opción --publish-local-settings publica los valores locales desde el archivo local.settings.json en Azure, por lo que no es necesario configurarlos de nuevo en Azure.

Habilitación de la autenticación de App Service

Azure Functions admite la autenticación con Microsoft Entra ID, Facebook, Twitter, cuenta de Microsoft y Google. En este tutorial, usará Microsoft como proveedor de identidades.

  1. En Azure Portal, vaya a la página de recursos de la aplicación de funciones.

  2. Seleccione Configuración>Autenticación.

  3. Seleccione Agregar el proveedor de identidades.

    Captura de pantalla de la página Autenticación de la aplicación de funciones y el botón para agregar un proveedor de identidades.

  4. En la lista Proveedor de identidades, seleccione Microsoft. Luego, seleccione Agregar.

    Captura de pantalla de la página para agregar un proveedor de identidades.

La configuración completada crea un registro de aplicación que asocia el proveedor de identidades a la aplicación de funciones.

Para obtener más información sobre los proveedores de identidades admitidos, consulte los artículos siguientes:

Prueba de la aplicación

  1. Abierto https://<YOUR-FUNCTION-APP-NAME>.azurewebsites.net/api/index.
  2. Seleccione Iniciar sesión para autenticarse con el proveedor de autenticación de su elección.
  3. Para enviar mensajes públicos, escríbalos en el cuadro de chat principal.
  4. Para enviar mensajes privados, seleccione un nombre de usuario en el historial de chat. Solo el destinatario seleccionado recibirá estos mensajes.

Captura de pantalla de una aplicación de chat de cliente en línea autenticada.

Felicidades. Ha implementado una aplicación de chat en tiempo real, sin servidor.

¿Tiene problemas? Cuéntenoslo.

Limpieza de recursos

Para limpiar los recursos que ha creado en este tutorial, elimine el grupo de recursos mediante Azure Portal.

Precaución

Al eliminar un grupo de recursos, se eliminan todos los recursos que contiene. Si el grupo de recursos contiene recursos que están fuera del ámbito de este tutorial, también se eliminarán.

¿Tiene problemas? Háganoslo saber.

Pasos siguientes

En este tutorial, ha aprendido a usar Azure Functions con Azure SignalR Service. Conozca más información sobre la creación de aplicaciones sin servidor en tiempo real con enlaces de Azure SignalR Service para Azure Functions:

¿Tiene problemas? Cuéntenoslo.