Uso de identidades de usuario en la autenticación de Azure App Service

Este artículo le muestra cómo trabajar con identidades de usuario al usar la autenticación y autorización integradas en App Service.

Acceso a notificaciones de usuario en el código de la aplicación

En todos los marcos de lenguaje, App Service hace que las notificaciones del token de entrada (tanto si proceden de un usuario final autenticado como de una aplicación cliente) estén disponibles para el código. Para ello, se insertan en los encabezados de solicitud. Las solicitudes externas no están autorizadas para establecer estos encabezados, por lo que solo están presentes si App Service los establece. A continuación puede ver algunos encabezados de ejemplo:

Encabezado Descripción
X-MS-CLIENT-PRINCIPAL Representación JSON codificada en Base64 de notificaciones disponibles. Para más información, consulte Decodificación del encabezado de entidad de seguridad del cliente.
X-MS-CLIENT-PRINCIPAL-ID Identificador del autor de la llamada establecido por el proveedor de identidades.
X-MS-CLIENT-PRINCIPAL-NAME Un nombre legible para el autor de la llamada que establece el proveedor de identidades, por ejemplo, dirección de correo electrónico, nombre principal de usuario.
X-MS-CLIENT-PRINCIPAL-IDP Nombre del proveedor de identidad utilizado por la autenticación de App Service.

Los tokens de proveedor también se exponen a través de encabezados similares. Por ejemplo, el proveedor de identidades de Microsoft también establece X-MS-TOKEN-AAD-ACCESS-TOKEN y X-MS-TOKEN-AAD-ID-TOKEN según corresponda.

Nota

Los distintos marcos de lenguaje pueden presentar estos encabezados al código de la aplicación en formatos diferentes, como minúsculas o mayúsculas.

El código escrito en cualquier lenguaje o plataforma puede obtener la información que necesita de estos encabezados. La decodificación del encabezado de entidad de seguridad del cliente cubre este proceso. En algunos marcos, la plataforma también proporciona otras opciones que podrían ser más convenientes.

Decodificación del encabezado de entidad de seguridad del cliente

X-MS-CLIENT-PRINCIPAL contiene el conjunto completo de notificaciones disponibles como JSON codificado en Base64. Estas notificaciones pasan por un proceso de asignación de notificaciones predeterminado, por lo que algunos pueden tener nombres diferentes de los que vería si procesara el token directamente. La carga útil decodificada está estructurada de la siguiente manera:

{
    "auth_typ": "",
    "claims": [
        {
            "typ": "",
            "val": ""
        }
    ],
    "name_typ": "",
    "role_typ": ""
}
Propiedad Tipo Description
auth_typ string Nombre del proveedor de identidad utilizado por la autenticación de App Service.
claims matriz de objetos Matriz de objetos que representan las notificaciones disponibles. Cada objeto contiene las propiedades typ y val.
typ string El nombre de la notificación. Esto puede haber estado sujeto a la asignación de notificaciones predeterminada y podría ser diferente de la notificación correspondiente contenida en un token.
val string Valor de la reclamación.
name_typ string El tipo de notificación de nombre, que suele ser un URI que proporciona información de esquema sobre la notificación name, si se ha definido una.
role_typ string El tipo de notificación de rol, que suele ser un URI que proporciona información de esquema sobre la notificación role, si se ha definido una.

Para procesar este encabezado, la aplicación deberá descodificar la carga útil e iterar a través de la matriz claims para buscar las notificaciones de interés. Puede ser conveniente convertirlos en una representación utilizada por el marco de lenguaje de la aplicación. Este es un ejemplo de este proceso en C# que construye un tipo ClaimsPrincipal para que la aplicación lo use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http;

public static class ClaimsPrincipalParser
{
    private class ClientPrincipalClaim
    {
        [JsonPropertyName("typ")]
        public string Type { get; set; }
        [JsonPropertyName("val")]
        public string Value { get; set; }
    }

    private class ClientPrincipal
    {
        [JsonPropertyName("auth_typ")]
        public string IdentityProvider { get; set; }
        [JsonPropertyName("name_typ")]
        public string NameClaimType { get; set; }
        [JsonPropertyName("role_typ")]
        public string RoleClaimType { get; set; }
        [JsonPropertyName("claims")]
        public IEnumerable<ClientPrincipalClaim> Claims { get; set; }
    }

    public static ClaimsPrincipal Parse(HttpRequest req)
    {
        var principal = new ClientPrincipal();

        if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
        {
            var data = header[0];
            var decoded = Convert.FromBase64String(data);
            var json = Encoding.UTF8.GetString(decoded);
            principal = JsonSerializer.Deserialize<ClientPrincipal>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
        }

        /** 
         *  At this point, the code can iterate through `principal.Claims` to
         *  check claims as part of validation. Alternatively, we can convert
         *  it into a standard object with which to perform those checks later
         *  in the request pipeline. That object can also be leveraged for 
         *  associating user data, etc. The rest of this function performs such
         *  a conversion to create a `ClaimsPrincipal` as might be used in 
         *  other .NET code.
         */

        var identity = new ClaimsIdentity(principal.IdentityProvider, principal.NameClaimType, principal.RoleClaimType);
        identity.AddClaims(principal.Claims.Select(c => new Claim(c.Type, c.Value)));
        
        return new ClaimsPrincipal(identity);
    }
}

Alternativas específicas del marco

Para las aplicaciones de ASP.NET 4.6, App Service rellena ClaimsPrincipal.Current con las notificaciones del usuario autenticado, de forma que usted puede seguir el patrón de código de .NET estándar, incluido el atributo [Authorize]. De forma similar, para las aplicaciones PHP, App Service rellena la variable _SERVER['REMOTE_USER']. En el caso de las aplicaciones Java, se puede acceder a las notificaciones desde el servlet Tomcat.

Para Azure Functions, ClaimsPrincipal.Current no está relleno para el código .NET, pero todavía puede encontrar las notificaciones de usuario en los encabezados de solicitudes, u obtener el objeto ClaimsPrincipal del contexto de la solicitud o incluso a través de un parámetro de enlace. Para más información, consulte Uso de identidades de cliente en Azure Functions.

Para .NET Core, Microsoft.Identity.Web admite rellenar el usuario actual con la autenticación de App Service. Para más información, vea la wiki de Microsoft.Identity.Web o consulte una demostración en este tutorial para una aplicación web que accede a Microsoft Graph.

Nota

Para que la asignación de notificaciones funcione, debe habilitar el almacén de tokens.

Acceso a notificaciones de usuario mediante la API

Si el almacén de tokens está habilitado para la aplicación, también puede obtener otros detalles sobre el usuario autenticado mediante una llamada a /.auth/me.

Pasos siguientes