Trabalhar com identidades de usuário na autenticação do Serviço de Aplicativo do Azure

Este artigo mostra como trabalhar com identidades de usuário ao usar a autenticação e autorização internas no Serviço de Aplicativo.

Acessar declarações de usuário no código do aplicativo

Para todas as estruturas de linguagem, o Serviço de Aplicativo disponibiliza as declarações no token de entrada (seja de um usuário final autenticado ou de um aplicativo cliente) para seu código injetando-as nos cabeçalhos de solicitação. As solicitações externas não têm permissão para definir esses cabeçalhos, portanto, eles estão presentes somente se definidos pelo Serviço de Aplicativo. Alguns exemplos de cabeçalhos incluem:

Cabeçalho Description
X-MS-CLIENT-PRINCIPAL Uma representação JSON codificada em Base64 das declarações disponíveis. Para obter mais informações, consulte Decodificando o cabeçalho principal do cliente.
X-MS-CLIENT-PRINCIPAL-ID Um identificador para o chamador definido pelo provedor de identidade.
X-MS-CLIENT-PRINCIPAL-NAME Um nome legível por humanos para o chamador definido pelo provedor de identidade, como endereço de e-mail ou nome principal do usuário.
X-MS-CLIENT-PRINCIPAL-IDP O nome do provedor de identidade usado pela Autenticação do Serviço de Aplicativo.

Os tokens de provedor também são expostos por meio de cabeçalhos semelhantes. Por exemplo, o Microsoft Entra também define X-MS-TOKEN-AAD-ACCESS-TOKEN e X-MS-TOKEN-AAD-ID-TOKEN conforme apropriado.

Nota

Diferentes estruturas de linguagem podem apresentar esses cabeçalhos ao código do aplicativo em formatos diferentes, como minúsculas ou minúsculas.

O código escrito em qualquer linguagem ou estrutura pode obter as informações necessárias a partir desses cabeçalhos. A decodificação do cabeçalho principal do cliente abrange esse processo. Para algumas estruturas, a plataforma também fornece opções extras que podem ser mais convenientes.

Decodificando o cabeçalho principal do cliente

X-MS-CLIENT-PRINCIPAL contém o conjunto completo de declarações disponíveis como JSON codificado em Base64. Essas declarações passam por um processo de mapeamento de declarações padrão, portanto, algumas podem ter nomes diferentes do que você veria se processasse o token diretamente. A carga útil descodificada está estruturada da seguinte forma:

{
    "auth_typ": "",
    "claims": [
        {
            "typ": "",
            "val": ""
        }
    ],
    "name_typ": "",
    "role_typ": ""
}
Propriedade Type Description
auth_typ string O nome do provedor de identidade usado pela Autenticação do Serviço de Aplicativo.
claims matriz de objetos Uma matriz de objetos que representa as declarações disponíveis. Cada objeto contém typ e val propriedades.
typ string O nome da reivindicação. Ele pode estar sujeito ao mapeamento de declarações padrão e pode ser diferente da declaração correspondente contida em um token.
val string O valor da afirmação.
name_typ string O tipo de declaração de nome, que normalmente é um URI que fornece informações de esquema sobre a name declaração, se uma for definida.
role_typ string O tipo de declaração de função, que normalmente é um URI que fornece informações de esquema sobre a role declaração, se uma for definida.

Para processar esse cabeçalho, seu aplicativo precisa decodificar a carga útil e iterar através da claims matriz para encontrar as reivindicações de interesse. Pode ser conveniente convertê-los em uma representação usada pela estrutura de linguagem do aplicativo. Aqui está um exemplo desse processo em C# que constrói um tipo ClaimsPrincipal para o aplicativo usar:

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 ao quadro

Para aplicativos ASP.NET 4.6, o Serviço de Aplicativo preenche ClaimsPrincipal.Current com as declarações do usuário autenticado, para que você possa seguir o padrão de código .NET padrão, incluindo o [Authorize] atributo. Da mesma forma, para aplicativos PHP, o Serviço de Aplicativo preenche a _SERVER['REMOTE_USER'] variável. Para aplicativos Java, as declarações são acessíveis a partir do servlet Tomcat.

Para o Azure Functions, ClaimsPrincipal.Current não é preenchido para código .NET, mas você ainda pode encontrar as declarações de usuário nos cabeçalhos de solicitação ou obter o ClaimsPrincipal objeto do contexto da solicitação ou até mesmo por meio de um parâmetro de ligação. Para obter mais informações, consulte Trabalhando com identidades de cliente no Azure Functions.

Para o .NET Core, o Microsoft.Identity.Web oferece suporte ao preenchimento do usuário atual com a autenticação do Serviço de Aplicativo. Para saber mais, você pode ler sobre isso no wiki Microsoft.Identity.Web ou vê-lo demonstrado neste tutorial para um aplicativo Web que acessa o Microsoft Graph.

Nota

Para que o mapeamento de declarações funcione, você deve habilitar o repositório de tokens.

Acessar declarações de usuário usando a API

Se o repositório de tokens estiver habilitado para seu aplicativo, você também poderá obter outros detalhes sobre o usuário autenticado chamando /.auth/me.

Próximos passos