Compartilhar via


Autenticação e autorização

Dica

Esse conteúdo é um trecho do livro eletrônico, Padrões de Aplicativo Empresarial Usando .NETMAUI, disponível em .NET Docs ou em PDF para download gratuito que pode ser lido off-line.

Miniatura da capa do livro eletrônico MAUI Padrões de aplicativo empresarial usando .NET.

A autenticação é o processo de obtenção de credenciais de identificação, como nome e senha de um usuário e validação dessas credenciais em relação a uma autoridade. A entidade que enviou as credenciais é considerada uma identidade autenticada se as credenciais forem válidas. Depois que uma identidade é estabelecida, um processo de autorização determina se essa identidade tem acesso a um determinado recurso.

Há muitas abordagens para integrar a autenticação e a autorização em um aplicativo MAUI .NET que se comunica com um aplicativo Web ASP.NET, incluindo o ASP.NET Core Identity, provedores de autenticação externa, como Microsoft, Google, Facebook ou Twitter, e middleware de autenticação. O aplicativo multiplataforma eShop executa autenticação e autorização com um microsserviço de identidade em contêiner que usa o IdentityServer. O aplicativo solicita tokens de segurança do IdentityServer para autenticar um usuário ou acessar um recurso. Para que o IdentityServer emita tokens em nome de um usuário, este deve entrar no IdentityServer. No entanto, o IdentityServer não fornece uma interface do usuário ou um banco de dados para autenticação. Portanto, no aplicativo de referência eShop, o ASP.NET Core Identity é utilizado para esse propósito.

Autenticação

A autenticação é necessária quando um aplicativo precisa saber a identidade do usuário atual. O principal mecanismo da ASP.NET Core para identificar usuários é o sistema de associação de identidade ASP.NET Core, que salva informações do usuário em um armazenamento de dados configurado pelo desenvolvedor. Normalmente, esse armazenamento de dados será um repositório EntityFramework, embora armazenamentos personalizados ou pacotes de terceiros possam ser usados para guardar informações de identidade no Azure, no DocumentDB ou em outros locais.

Para cenários de autenticação que usam um armazenamento de dados de usuário local e mantêm informações de identidade entre solicitações por meio de cookies (como é comum em ASP.NET aplicativos Web), o ASP.NET Core Identity é uma solução adequada. No entanto, os cookies nem sempre são um meio natural de manter e transmitir dados. Por exemplo, um aplicativo Web ASP.NET Core que expõe pontos de extremidade RESTful acessados de um aplicativo, normalmente precisará usar a autenticação de token de portador, pois os cookies não podem ser usados nesse cenário. No entanto, os tokens de portador podem ser facilmente recuperados e incluídos no cabeçalho de autorização de solicitações Web feitas do aplicativo.

Emissão de tokens de portador usando o IdentityServer

IdentityServer é uma estrutura OpenID Connect e OAuth 2.0 de código aberto para ASP.NET Core, que pode ser usada para muitos cenários de autenticação e autorização, incluindo a emissão de tokens de segurança para usuários locais do ASP.NET Core Identity.

Observação

O OpenID Connect e o OAuth 2.0 são muito semelhantes, embora tenham responsabilidades diferentes.

OpenID Connect é uma camada de autenticação sobre o protocolo OAuth 2.0. OAuth 2 é um protocolo que permite aos aplicativos solicitar tokens de acesso de um serviço de token de segurança e usá-los para se comunicar com APIs. Essa delegação reduz a complexidade dos aplicativos cliente e das APIs, pois a autenticação e a autorização podem ser centralizadas.

O OpenID Connect e o OAuth 2.0 combinam as duas preocupações fundamentais de segurança de autenticação e acesso à API, e o IdentityServer é uma implementação desses protocolos.

Em aplicativos que usam comunicação direta entre cliente e microsserviço, como o aplicativo de referência eShop, um microsserviço de autenticação dedicado que atua como um Serviço de Token de Segurança (STS) pode ser usado para autenticar usuários, conforme mostrado no diagrama a seguir. Para obter mais informações sobre a comunicação direta entre cliente e microsserviço, confira Microsserviços.

Autenticação por um microsserviço de autenticação dedicado.

O aplicativo multiplataforma eShop se comunica com o microsserviço de identidade, que usa o IdentityServer para realizar a autenticação e o controle de acesso às APIs. Portanto, o aplicativo multiplataforma solicita tokens do IdentityServer, seja para autenticar um usuário ou para acessar um recurso:

  • A autenticação de usuários com IdentityServer é realizada pelo aplicativo multiplataforma solicitando um token de identidade, representando o resultado de um processo de autenticação. No mínimo, ele contém um identificador para o usuário e informações sobre como e quando o usuário é autenticado. Ele também pode incluir dados de identidade adicionais.
  • O acesso a um recurso com IdentityServer é obtido pelo aplicativo multiplataforma que solicita um token de acesso, o que permite o acesso a um recurso de API. Os clientes solicitam tokens de acesso e os encaminham para a API. Os tokens de acesso contêm informações sobre o cliente e o usuário, se houver. As APIs então usam essas informações para autorizar o acesso aos seus dados.

Observação

Um cliente deve ser registrado no IdentityServer antes de poder solicitar tokens com êxito. Para obter mais informações sobre como adicionar clientes, confira Como definir clientes.

Como adicionar IdentityServer a um aplicativo Web

Para que um aplicativo Web ASP.NET Core use o IdentityServer, ele deve ser adicionado à solução Visual Studio do aplicativo Web. Para obter mais informações, confira Configuração e visão geral na documentação do IdentityServer. Depois que o IdentityServer for incluído na solução do Visual Studio do aplicativo Web, ele deverá ser adicionado ao seu pipeline de processamento de solicitação HTTP para entregar as solicitações aos pontos de extremidade OpenID Connect e OAuth 2.0. Isso é configurado no Program.cs do projeto Identity.API, conforme demonstrado no exemplo de código a seguir:


...

app.UseIdentityServer();

A ordem é importante no pipeline de processamento de solicitação HTTP do aplicativo Web. Portanto, o IdentityServer deve ser adicionado ao pipeline antes da estrutura de interface do usuário que implementa a tela de logon.

Configuração do IdentityServer

O IdentityServer é configurado no Program.cs do projeto Identity.API chamando o método AddIdentityServer, conforme demonstrado no exemplo de código a seguir do aplicativo de referência da eShop:

builder.Services.AddIdentityServer(options =>
    {
        options.Authentication.CookieLifetime = TimeSpan.FromHours(2);
    
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
    
        // TODO: Remove this line in production.
        options.KeyManagement.Enabled = false;
    })
    .AddInMemoryIdentityResources(Config.GetResources())
    .AddInMemoryApiScopes(Config.GetApiScopes())
    .AddInMemoryApiResources(Config.GetApis())
    .AddInMemoryClients(Config.GetClients(builder.Configuration))
    .AddAspNetIdentity<ApplicationUser>()
    // TODO: Not recommended for production - you need to store your key material somewhere secure
    .AddDeveloperSigningCredential();

Depois de chamar o método services.AddIdentityServer, APIs fluentes adicionais são chamadas para configurar o seguinte:

  • Credenciais usadas para assinatura.
  • API e recursos de identidade aos quais os usuários podem solicitar acesso.
  • Os clientes que se conectarão para solicitar tokens.
  • Identidade do ASP.NET Core.

Dica

Carregar dinamicamente a configuração do IdentityServer. As APIs do IdentityServer permitem a configuração do IdentityServer a partir de uma lista de objetos de configuração na memória. No aplicativo de referência eShop, essas coleções na memória são codificadas no aplicativo. No entanto, em cenários de produção, eles podem ser carregados dinamicamente de um arquivo de configuração ou de um banco de dados.

Para obter informações sobre como configurar o IdentityServer para usar o ASP.NET Core Identity, confira Usando o ASP.NET Core Identity na documentação do IdentityServer.

Configuração de recursos de API

Ao configurar os recursos da API, o método AddInMemoryApiResources espera uma coleção IEnumerable<ApiResource>. O exemplo de código a seguir mostra o método GetApis que fornece essa coleção no aplicativo de referência eShop:

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiScope("orders", "Orders Service"),
        new ApiScope("basket", "Basket Service"),
        new ApiScope("webhooks", "Webhooks registration Service"),
    };
}

Esse método especifica que o IdentityServer deve proteger os pedidos e as APIs de cesta. Portanto, os tokens de acesso gerenciados pelo IdentityServer serão necessários ao fazer chamadas para essas APIs. Para obter mais informações sobre o tipo ApiResource, consulte Recursos da API na documentação do IdentityServer.

Configuração de recursos de identidade

Ao configurar recursos de identidade, o AddInMemoryIdentityResources método espera uma coleção IEnumerable<IdentityResource>. Recursos de identidade são dados como ID do usuário, nome ou endereço de email. Cada recurso de identidade tem um nome exclusivo e tipos de declaração arbitrários podem ser atribuídos a ele, que serão incluídos no token de identidade do usuário. O exemplo de código a seguir mostra o método GetResources que fornece essa coleção no aplicativo de referência eShop:

public static IEnumerable<IdentityResource> GetResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile()
    };
}

A especificação do OpenID Connect define alguns recursos de identidade padrão. O requisito mínimo é que seja fornecido suporte para a emissão de um ID exclusivo para os usuários. Isso é obtido expondo o recurso de identidade IdentityResources.OpenId.

Observação

A classe IdentityResources oferece suporte a todos os escopos definidos na especificação OpenID Connect (openid, email, perfil, telefone e endereço).

O IdentityServer também oferece suporte à definição de recursos de identidade personalizados. Para obter mais informações, confira Como definir recursos de identidade personalizados na documentação do IdentityServer. Para obter mais informações sobre o tipo IdentityResource, consulte Recurso de Identidade na documentação do IdentityServer.

Configuração de clientes

Os clientes são aplicativos que podem solicitar tokens do IdentityServer. Normalmente, as seguintes configurações devem ser definidas para cada cliente como requisito mínimo:

  • Uma ID de cliente exclusiva.
  • As interações permitidas com o serviço de token (conhecido como tipo de concessão).
  • O local para o qual os tokens de identidade e acesso serão enviados (conhecido como URI de redirecionamento).
  • Uma lista de recursos aos quais o cliente tem permissão de acesso (conhecidos como escopos).

Ao configurar clientes, o método AddInMemoryClients espera uma coleção IEnumerable<Client>. O exemplo de código a seguir mostra a configuração do aplicativo multiplataforma eShop no método GetClients que fornece essa coleção no aplicativo de referência eShop:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        // Omitted for brevity
        new Client
        {
            ClientId = "maui",
            ClientName = "eShop MAUI OpenId Client",
            AllowedGrantTypes = GrantTypes.Code,                    
            //Used to retrieve the access token on the back channel.
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { configuration["MauiCallback"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{configuration["MauiCallback"]}/Account/Redirecting" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket",
                "mobileshoppingagg",
                "webhooks"
            },
            //Allow requesting refresh tokens for long lived API access
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true,
            AlwaysIncludeUserClaimsInIdToken = true,
            AccessTokenLifetime = 60 * 60 * 2, // 2 hours
            IdentityTokenLifetime = 60 * 60 * 2 // 2 hours
        }
    };
}

Essa configuração especifica dados para as seguintes propriedades:

Propriedade Descrição
ClientId Uma ID exclusiva para o cliente.
ClientName O nome de exibição do cliente, que é usado para registro em log e a tela de consentimento.
AllowedGrantTypes Especifica como um cliente deseja interagir com o IdentityServer. Para obter mais informações, confira Configuração do fluxo de autenticação.
ClientSecrets Especifica as credenciais de segredo do cliente usadas ao solicitar tokens do ponto de extremidade do token.
RedirectUris Especifica os URIs permitidos para os quais retornar tokens ou códigos de autorização.
RequireConsent Especifica se uma tela de consentimento é necessária.
RequirePkce Especifica se os clientes que usam um código de autorização devem enviar uma chave de prova.
PostLogoutRedirectUris Especifica os URIs permitidos para redirecionar após o logout.
AllowedCorsOrigins Especifica a origem do cliente para que o IdentityServer possa permitir chamadas com suporte de origem cruzada.
AllowedScopes Especifica os recursos aos quais o cliente tem acesso. Por padrão, um cliente não tem acesso a nenhum recurso.
AllowOfflineAccess Especifica se o cliente pode solicitar tokens de atualização.
AllowAccessTokensViaBrowser Especifica se o cliente pode receber tokens de acesso de uma janela do navegador.
AlwaysIncludeUserClaimsInIdToken Especifica que as declarações do usuário sempre serão adicionadas ao token de identidade. Por padrão, elas teriam de ser recuperadas usando o ponto de extremidade userinfo.
AccessTokenLifetime Especifica o tempo de vida do token de acesso em segundos.
IdentityTokenLifetime Especifica a vida útil do token de identidade em segundos.

Configuração do fluxo de autenticação

O fluxo de autenticação entre um cliente e o IdentityServer pode ser configurado especificando os tipos de concessão na propriedade Client.AllowedGrantTypes. As especificações OpenID Connect e OAuth 2.0 definem vários fluxos de autenticação, incluindo:

Fluxo de autenticação Descrição
Implícita Esse fluxo é otimizado para aplicativos baseados em navegador e deve ser usado apenas para autenticação do usuário ou solicitações de autenticação e token de acesso. Todos os tokens são transmitidos pelo navegador e, portanto, recursos avançados, como tokens de atualização, não são permitidos.
Código de Autorização Esse fluxo fornece a capacidade de recuperar tokens em um canal de fundo, em oposição ao canal frontal do navegador, além de oferecer suporte à autenticação do cliente.
Híbrido Esse fluxo é uma combinação dos tipos de concessão implícita e de código de autorização. O token de identidade é transmitido pelo canal do navegador e contém a resposta do protocolo assinado e outros artefatos, como o código de autorização. Depois de validar a resposta com sucesso, o canal de retorno deve ser usado para recuperar o token de acesso e atualização.

Dica

Considere usar o fluxo de autenticação híbrida. O fluxo de autenticação híbrida mitiga uma série de ataques que se aplicam ao canal do navegador, e é o fluxo recomendado para aplicativos nativos que desejam recuperar tokens de acesso (e possivelmente tokens de atualização).

Para obter mais informações sobre fluxos de autenticação, consulte Tipos de Concessão na documentação do IdentityServer.

Execução da autenticação

Para que o IdentityServer emita tokens em nome de um usuário, este deve entrar no IdentityServer. No entanto, o IdentityServer não fornece uma interface do usuário ou um banco de dados para autenticação. Portanto, no aplicativo de referência eShop, o ASP.NET Core Identity é utilizado para esse propósito.

O aplicativo multiplataforma eShop se autentica no IdentityServer com o fluxo de autenticação híbrida, que é ilustrado no diagrama abaixo.

Visão geral de alto nível do processo de login.

Uma solicitação de entrada é feita para <base endpoint>:5105/connect/authorize. Após a autenticação bem-sucedida, o IdentityServer retorna uma resposta de autenticação contendo um código de autorização e um token de identidade. O código de autorização é enviado para <base endpoint>:5105/connect/token, que responde com tokens de acesso, identidade e atualização.

O aplicativo multiplataforma eShop se desconecta do IdentityServer enviando uma solicitação para <base endpoint>:5105/connect/endsession com parâmetros adicionais. Após a saída, o Identity Server responde enviando um URI de redirecionamento pós-logoff de volta ao aplicativo multiplataforma. O diagrama abaixo ilustra esse processo.

Visão geral de alto nível do processo de saída.

No aplicativo multiplataforma eShop, a comunicação com o IdentityServer é realizada pela classe IdentityService, que implementa a interface IIdentityService. Essa interface especifica que a classe de implementação deve fornecer os métodos SignInAsync, SignOutAsync, GetUserInfoAsync e GetAuthTokenAsync.

Como usar suas credenciais

Quando o usuário toca no botão do LOGIN emLoginView, o SignInCommand da classe LoginViewModel é executado, que por sua vez executa o método SignInAsync. O seguinte exemplo de código mostra esse método:

[RelayCommand]
private async Task SignInAsync()
{
    await IsBusyFor(
        async () =>
        {
            var loginSuccess = await _appEnvironmentService.IdentityService.SignInAsync();

            if (loginSuccess)
            {
                await NavigationService.NavigateToAsync("//Main/Catalog");
            }
        });
}

Esse método invoca o método SignInAsync na classe IdentityService, conforme mostrado no exemplo de código a seguir:

public async Task<bool> SignInAsync()
{
    var response = await GetClient().LoginAsync(new LoginRequest()).ConfigureAwait(false);

    if (response.IsError)
    {
        return false;
    }

    await _settingsService
        .SetUserTokenAsync(
            new UserToken
            {
                AccessToken = response.AccessToken,
                IdToken = response.IdentityToken,
                RefreshToken = response.RefreshToken,
                ExpiresAt = response.AccessTokenExpiration
            })
        .ConfigureAwait(false);

    return !response.IsError;
}

O IdentityService faz uso do OidcClient fornecido com o IdentityModel.OidcClient NuGet. Esse cliente exibe a visualização da Web de autenticação para o usuário no aplicativo e captura o resultado da autenticação. O cliente se conecta ao URI do ponto de extremidade de autorização do IdentityServer com os parâmetros necessários. O ponto de extremidade de autorização está em /connect/authorize na porta 5105 do ponto de extremidade base exposto como uma configuração de usuário. Para obter mais informações sobre as configurações do usuário, confira Gerenciamento de Configurações.

Observação

A superfície de ataque do aplicativo multiplataforma eShop é reduzida pela implementação da extensão Chave de Prova para Troca de Código (PKCE) no OAuth. O PKCE protegerá o código de autorização de ser usado se ele for interceptado. Esse resultado é alcançado pelo cliente gerando um verificador de segredo, um hash do qual é passado na solicitação de autorização e que é apresentado sem hash ao resgatar o código de autorização. Para obter mais informações sobre o PKCE, confira Chave de Prova para Troca de Códigos por Clientes Públicos OAuth no site da Força-Tarefa de Engenharia da Internet.

Página de login exibida pelo WebView.

Se o ponto de extremidade do token receber informações válidas de autenticação, código de autorização e verificador de segredo PKCE, ele responderá com um token de acesso, token de identidade e token de atualização. O token de acesso (que permite o acesso aos recursos de API) e o de identidade são armazenados como configurações de aplicativo e a navegação de página é executada. Portanto, o efeito geral no aplicativo multiplataforma eShop é o seguinte: desde que os usuários consigam se autenticar com sucesso no IdentityServer, eles são direcionados para a rota //Main/Catalog, que é um TabbedPage que exibe o CatalogView como sua guia selecionada.

Para obter informações sobre navegação de página, confira Navegação. Para obter informações sobre como a navegação do WebView faz com que um método de modelo de exibição seja executado, confira Como invocar a navegação usando comportamentos. Para obter informações sobre as configurações do aplicativo, confira Gerenciamento de configuração.

Observação

O eShop também permite uma entrada simulada quando o aplicativo está configurado para usar serviços simulados no SettingsView. Nesse modo, o aplicativo não se comunica com o IdentityServer, permitindo que o usuário entre usando credenciais.

Saída

Quando o usuário toca no botão do LOG OUT emProfileView, o LogoutCommand da classe ProfileViewModel é executado, que por sua vez executa o método LogoutAsync. Esse método executa a navegação na página LoginView, passando um parâmetro de consulta Logout definido como true.

Esse parâmetro é avaliado no método ApplyQueryAttributes. Se o parâmetro Logout estiver presente com um valor true, o método PerformLogoutAsync da classe LoginViewModel será executado, conforme mostrado no exemplo de código a seguir:

private async Task PerformLogoutAsync()
{
    await _appEnvironmentService.IdentityService.SignOutAsync();

    _settingsService.UseFakeLocation = false;

    UserName.Value = string.Empty;
    Password.Value = string.Empty;
}

Esse método invoca o método SignOutAsync na classe IdentityService, que invoca o método OidcClient para encerrar a sessão do usuário e limpar os tokens de usuário salvos. Para obter mais informações sobre as configurações do aplicativo, confira Gerenciamento de configuração. O seguinte exemplo de código mostra o método SignOutAsync:

public async Task<bool> SignOutAsync()
{
    var response = await GetClient().LogoutAsync(new LogoutRequest()).ConfigureAwait(false);

    if (response.IsError)
    {
        return false;
    }

    await _settingsService.SetUserTokenAsync(default);

    return !response.IsError;
}

Este método utiliza o OidcClient para chamar o URI do ponto de extremidade de encerramento de sessão do IdentityServer com os parâmetros necessários. O ponto de extremidade da sessão final está em /connect/endsession na porta 5105 do ponto de extremidade base exposto como uma configuração de usuário. Depois que o usuário tiver se desconectado com êxito, LoginView será apresentado ao usuário e todas as informações salvas do usuário serão apagadas.

Para obter informações sobre navegação de página, confira Navegação. Para obter informações sobre como a navegação de WebView faz com que um método de modelo de exibição seja executado, confira Como invocar a navegação usando comportamentos. Para obter informações sobre as configurações do aplicativo, confira Gerenciamento de configuração.

Observação

O eShop também permite uma saída simulada quando o aplicativo está configurado para usar serviços simulados no SettingsView. Nesse modo, o aplicativo não se comunica com o IdentityServer e, em vez disso, limpa todos os tokens armazenados das configurações do aplicativo.

Autorização

Após a autenticação, as APIs Web do ASP.NET Core geralmente precisam autorizar o acesso, o que permite que um serviço disponibilize APIs para alguns usuários autenticados, mas não para todos.

A restrição de acesso a uma rota ASP.NET Core pode ser obtida aplicando um atributo de Autorização a um controlador ou ação, que limita o acesso ao controlador ou ação a usuários autenticados, conforme mostrado no exemplo de código a seguir:

[Authorize]
public sealed class BasketController : Controller
{
    // Omitted for brevity
}

Se um usuário não autorizado tentar acessar um controlador ou ação marcada com o atributo Authorize, a estrutura da API retornará um código de status HTTP 401 (unauthorized).

Observação

Os parâmetros podem ser especificados no atributo de Autorização para restringir uma API a usuários específicos. Para obter mais informações, confira Documentação do ASP.NET Core: Autorização.

O IdentityServer pode ser integrado ao fluxo de trabalho de autorização para que os tokens de acesso forneçam uma autorização de controle. Essa abordagem é mostrada no diagrama abaixo.

Autorização por token de acesso.

O aplicativo multiplataforma eShop se comunica com o microsserviço de identidade e solicita um token de acesso como parte do processo de autenticação. O token de acesso é então encaminhado para as APIs expostas pelos microsserviços de pedido e cesta como parte das solicitações de acesso. Os tokens de acesso contêm informações sobre o cliente e o usuário. As APIs então usam essas informações para autorizar o acesso aos seus dados. Para obter informações sobre como configurar o IdentityServer para proteger APIs, confira Configuração de recursos de API.

Configuração do IdentityServer para executar a autorização

Para executar a autorização com o IdentityServer, o middleware correspondente deve ser adicionado ao pipeline de solicitação HTTP do aplicativo Web. O middleware é adicionado no método de extensão AddDefaultAuthentication, que é invocado a partir do método AddApplicationServices na classe Program e é demonstrado no seguinte exemplo de código do aplicativo de referência eShop:

public static IServiceCollection AddDefaultAuthentication(this IHostApplicationBuilder builder)
{
    var services = builder.Services;
    var configuration = builder.Configuration;

    var identitySection = configuration.GetSection("Identity");

    if (!identitySection.Exists())
    {
        // No identity section, so no authentication
        return services;
    }

    // prevent from mapping "sub" claim to nameidentifier.
    JsonWebTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");

    services.AddAuthentication().AddJwtBearer(options =>
    {
        var identityUrl = identitySection.GetRequiredValue("Url");
        var audience = identitySection.GetRequiredValue("Audience");

        options.Authority = identityUrl;
        options.RequireHttpsMetadata = false;
        options.Audience = audience;
        options.TokenValidationParameters.ValidIssuers = [identityUrl];
        options.TokenValidationParameters.ValidateAudience = false;
    });

    services.AddAuthorization();

    return services;
}

Esse método garante que a API só possa ser acessada com um token de acesso válido. O middleware valida o token de entrada para garantir que ele seja enviado de um emissor confiável e valida o token para uso usado com a API que o recebe. Portanto, navegar até o controlador de ordenação ou cesta retornará um código de status HTTP 401 (unauthorized), indicando que um token de acesso é necessário.

Fazer solicitações de acesso a APIs

Ao fazer solicitações para os microsserviços de pedido e cesta, o token de acesso obtido do IdentityServer durante o processo de autenticação deve ser incluído na solicitação, conforme mostrado no exemplo de código a seguir:

public async Task CreateOrderAsync(Models.Orders.Order newOrder)
{
    var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);

    if (string.IsNullOrEmpty(authToken))
    {
        return;
    }

    var uri = $"{UriHelper.CombineUri(_settingsService.GatewayOrdersEndpointBase, ApiUrlBase)}?api-version=1.0";

    var success = await _requestProvider.PostAsync(uri, newOrder, authToken, "x-requestid").ConfigureAwait(false);
}

O token de acesso é armazenado com a implementação IIdentityService e pode ser recuperado usando o método GetAuthTokenAsync.

Da mesma forma, o token de acesso deve ser incluído ao enviar dados para uma API protegida pelo IdentityServer, conforme mostrado no exemplo de código a seguir:

public async Task ClearBasketAsync()
{
    var authToken = await _identityService.GetAuthTokenAsync().ConfigureAwait(false);

    if (string.IsNullOrEmpty(authToken))
    {
        return;
    }

    await GetBasketClient().DeleteBasketAsync(new DeleteBasketRequest(), CreateAuthenticationHeaders(authToken))
        .ConfigureAwait(false);
}

O token de acesso é recuperado do IIdentityService e incluído na chamada ao método ClearBasketAsync na classe BasketService.

A classe RequestProvider no aplicativo multiplataforma eShop usa a classe HttpClient para fazer solicitações às APIs RESTful expostas pelo aplicativo de referência da eShop. Ao fazer solicitações para as APIs de pedido e cesta, que requerem autorização, um token de acesso válido deve ser incluído na solicitação. Isso é obtido adicionando o token de acesso aos cabeçalhos da instância HttpClient, conforme demonstrado no exemplo de código a seguir:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

A propriedade DefaultRequestHeaders da classe HttpClient expõe os cabeçalhos que são enviados com cada solicitação e o token de acesso é adicionado ao cabeçalho Authorization prefixado com a cadeia de caracteres Bearer. Quando a solicitação é enviada para uma API RESTful, o valor do cabeçalho Authorization é extraído e validado para garantir que ele seja enviado de um emissor confiável e usado para determinar se o usuário tem permissão para invocar a API que a recebe.

Para obter mais informações sobre como o aplicativo multiplataforma eShop faz solicitações da Web, consulte Acessando dados remotos.

Resumo

Há muitas abordagens para integrar autenticação e autorização em um aplicativo MAUI .NET que se comunica com um aplicativo Web ASP.NET. O aplicativo multiplataforma eShop executa autenticação e autorização com um microsserviço de identidade em contêiner que usa o IdentityServer. O IdentityServer é uma estrutura OpenID Connect e OAuth 2.0 de código aberto para ASP.NET Core que se integra ao ASP.NET Core Identity para executar a autenticação de token de portador.

O aplicativo multiplataforma solicita tokens de segurança do IdentityServer para autenticar um usuário ou acessar um recurso. Ao acessar um recurso, um token de acesso deve ser incluído na solicitação para APIs que requerem autorização. O middleware do IdentityServer valida os tokens de acesso de entrada para garantir que eles sejam enviados de um emissor confiável e que sejam válidos para serem usados com a API que os recebe.