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 a autorização internas no Serviço de Aplicativo.

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

Em 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 o seu código injetando-as nos cabeçalhos de solicitação. Solicitações externas não são permitidas para definir esses cabeçalhos, portanto são apresentadas somente se definido pelo Serviço de Aplicativo. Alguns cabeçalhos de exemplo incluem:

parâmetro Descrição
X-MS-CLIENT-PRINCIPAL Uma representação JSON codificada em Base64 de declarações disponíveis. Para obter mais informações, confira Como decodificar o cabeçalho da entidade de segurança 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 para o chamador definido pelo provedor de identidade, por exemplo, Endereço de Email, Nome UPN.
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 Provedor de Identidade da Microsoft também define X-MS-TOKEN-AAD-ACCESS-TOKEN e X-MS-TOKEN-AAD-ID-TOKEN conforme apropriado.

Observação

Estruturas de linguagem diferentes podem apresentar os cabeçalhos para o código do aplicativo em diferentes formatos, como letras minúsculas ou de título.

Um código escrito em qualquer linguagem ou estrutura pode obter as informações necessárias desses cabeçalhos. O artigo Como decodificar o cabeçalho da entidade de segurança do cliente aborda esse processo. Para algumas estruturas, a plataforma também fornece opções adicionais que podem ser mais convenientes.

Como decodificar o cabeçalho da entidade de segurança 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. O conteúdo da resposta é estrutura conforme a seguir:

{
    "auth_typ": "",
    "claims": [
        {
            "typ": "",
            "val": ""
        }
    ],
    "name_typ": "",
    "role_typ": ""
}
Propriedade Type Descrição
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 representam as declarações disponíveis. Cada objeto contém as propriedades typ e val.
typ string O nome da declaração. Isso 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 declaração.
name_typ string O tipo de declaração de nome, que normalmente é um URI que fornece informações de esquema sobre a declaração name se houver uma definida.
role_typ string O tipo de declaração de nome, que normalmente é um URI que fornece informações de esquema sobre a declaração role se houver uma definida.

Para processar esse cabeçalho, seu aplicativo precisará decodificar a carga e iterar pela matriz claims para localizar as declarações de interesse. Pode ser conveniente convertê-las 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 da estrutura

Para aplicativos ASP.NET 4.6, o Serviço de Aplicativo preenche ClaimsPrincipal.Current com as declarações do usuário autenticado, de modo que seja possível seguir o padrão de código .NET Standard, incluindo o atributo [Authorize]. Da mesma forma, para aplicativos PHP, o Serviço de Aplicativo preenche a variável _SERVER['REMOTE_USER']. Para aplicativos Java, as declarações podem ser acessadas por meio do servlet do Tomcat.

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

No caso do .NET Core, o Microsoft.Identity.Web oferece suporte à população 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 acessando o Microsoft Graph.

Observação

Para que o mapeamento das declarações funcione, você deve habilitar o Token Store.

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

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

Próximas etapas