Partilhar via


Autenticação e autorização

Observação

Este e-book foi publicado na primavera de 2017 e não foi atualizado desde então. Há muito no livro que permanece valioso, mas parte do material está desatualizado.

Autenticação é o processo de obter credenciais de identificação, como nome e senha de um usuário, e validar essas credenciais em relação a uma autoridade. Se as credenciais forem válidas, a entidade que as enviou será considerada uma identidade autenticada. Depois que uma identidade é autenticada, um processo de autorização determina se essa identidade tem acesso a um determinado recurso.

Há muitas abordagens para integrar autenticação e autorização em um Xamarin.Forms aplicativo que se comunica com um aplicativo Web MVC ASP.NET, incluindo o uso ASP.NET Identidade Principal, provedores de autenticação externos, como Microsoft, Google, Facebook ou Twitter, e middleware de autenticação. O aplicativo móvel eShopOnContainers executa autenticação e autorização com um microsserviço de identidade em contêiner que usa o IdentityServer 4. O aplicativo móvel solicita tokens de segurança do IdentityServer, seja para autenticar um usuário ou para acessar um recurso. Para que o IdentityServer emita tokens em nome de um usuário, o usuário 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 eShopOnContainers, o ASP.NET Core Identity é usado para essa finalidade.

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 do EntityFramework, embora repositórios personalizados ou pacotes de terceiros possam ser usados para armazenar informações de identidade no armazenamento do Azure, no Azure Cosmos DB ou em outros locais.

Para cenários de autenticação que usam um armazenamento de dados de usuário local e que persistem informações de identidade entre solicitações por meio de cookies (como é típico em ASP.NET aplicativos Web MVC), ASP.NET Identidade Principal é 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 que são acessados de um aplicativo móvel 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 da Web feitas no aplicativo móvel.

Emissão de tokens de portador usando o IdentityServer 4

O IdentityServer 4 é 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 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.

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

Em aplicativos que usam comunicação direta de cliente para microsserviço, como o aplicativo de referência eShopOnContainers, um microsserviço de autenticação dedicado atuando como um STS (Serviço de Token de Segurança) pode ser usado para autenticar usuários, conforme mostrado na Figura 9-1. Para obter mais informações sobre a comunicação direta do cliente para o microsserviço, consulte Comunicação entre o cliente e os microsserviços.

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

Figura 9-1: Autenticação por um microsserviço de autenticação dedicado

O aplicativo móvel eShopOnContainers se comunica com o microsserviço de identidade, que usa o IdentityServer 4 para executar a autenticação e o controle de acesso para APIs. Portanto, o aplicativo móvel solicita tokens do IdentityServer, seja para autenticar um usuário ou para acessar um recurso:

  • A autenticação de usuários com IdentityServer é obtida pelo aplicativo móvel solicitando um token de identidade , que representa 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 foi autenticado. Ele também pode conter dados de identidade adicionais.
  • O acesso a um recurso com IdentityServer é obtido pelo aplicativo móvel solicitando um token de acesso , 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 solicitar tokens.

Adicionando IdentityServer a um aplicativo Web

Para que um aplicativo Web ASP.NET Core use o IdentityServer 4, ele deve ser adicionado à solução Visual Studio do aplicativo Web. Para obter mais informações, consulte 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 pipeline de processamento de solicitação HTTP do aplicativo Web, para que ele possa atender a solicitações para pontos de extremidade OpenID Connect e OAuth 2.0. Isso é obtido no método Configure da classe Startup do aplicativo da Web, conforme demonstrado no exemplo de código a seguir:

public void Configure(  
    IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{  
    ...  
    app.UseIdentity();  
    ...  
}

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

IdentityServer deve ser configurado no ConfigureServices método na classe do Startup aplicativo Web chamando o services.AddIdentityServer método, conforme demonstrado no exemplo de código a seguir do aplicativo de referência eShopOnContainers:

public void ConfigureServices(IServiceCollection services)  
{  
    ...  
    services.AddIdentityServer(x => x.IssuerUri = "null")  
        .AddSigningCredential(Certificate.Get())                 
        .AddAspNetIdentity<ApplicationUser>()  
        .AddConfigurationStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .AddOperationalStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .Services.AddTransient<IProfileService, ProfileService>();  
}

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

Carregue dinamicamente a configuração do IdentityServer 4. As APIs do IdentityServer 4 permitem configurar o IdentityServer de uma lista na memória de objetos de configuração. No aplicativo de referência eShopOnContainers, 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.

Configurando 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 eShopOnContainers:

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

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

Configurando 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 designados 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 eShopOnContainers:

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 IdentityResources classe dá suporte a todos os escopos definidos na especificação OpenID Connect (openid, email, profile, telephone e address).

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

Como configurar 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 móvel eShopOnContainers no GetClients método que fornece essa coleção no aplicativo de referência eShopOnContainers:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        ...
        new Client
        {
            ClientId = "xamarin",
            ClientName = "eShop Xamarin OpenId Client",
            AllowedGrantTypes = GrantTypes.Hybrid,
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { clientsUrl["Xamarin"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
            AllowedCorsOrigins = { "http://eshopxamarin" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket"
            },
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true
        },
        ...
    };
}

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

  • 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 IdentityServer. Para obter mais informações, consulte Configurando o fluxo de autenticação.
  • ClientSecrets: Especifica as credenciais secretas do cliente que são 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 entre origens da origem.
  • 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.

Configurando o 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 do OpenID Connect e do OAuth 2.0 definem vários fluxos de autenticação, incluindo:

  • Implícito. 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 por meio do canal do navegador e contém a resposta do protocolo assinado junto com outros artefatos, como o código de autorização. Após a validação bem-sucedida da resposta, o canal de retorno deve ser usado para recuperar o token de acesso e atualização.

Dica

Use 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, confira Tipos de Concessão na documentação do IdentityServer 4.

Executando a autenticação

Para que o IdentityServer emita tokens em nome de um usuário, o usuário 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 eShopOnContainers, o ASP.NET Core Identity é usado para essa finalidade.

O aplicativo móvel eShopOnContainers é autenticado com o IdentityServer com o fluxo de autenticação híbrida, que é ilustrado na Figura 9-2.

Visão geral de alto nível do processo de entrada

Figura 9-2: Visão geral de alto nível do processo de entrada

Uma solicitação de logon é 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 é então enviado para <base endpoint>:5105/connect/tokeno , que responde com tokens de acesso, identidade e atualização.

O aplicativo móvel eShopOnContainers sai do IdentityServer enviando uma solicitação para <base endpoint>:5105/connect/endsession, com parâmetros adicionais. Depois que a saída ocorre, o IdentityServer responde enviando um URI de redirecionamento pós-logout de volta para o aplicativo móvel. A Figura 9-3 ilustra esse processo.

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

Figura 9-3: Visão geral de alto nível do processo de saída

No aplicativo móvel eShopOnContainers, a comunicação com IdentityServer é executada IdentityService pela classe, que implementa a IIdentityService interface. Essa interface especifica que a classe de implementação deve fornecer os métodos CreateAuthorizationRequest, CreateLogoutRequest e GetTokenAsync.

Como usar suas credenciais

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

private async Task SignInAsync()  
{  
    ...  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    IsLogin = true;  
    ...  
}

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

public string CreateAuthorizationRequest()
{
    // Create URI to authorization endpoint
    var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint);

    // Dictionary with values for the authorize request
    var dic = new Dictionary<string, string>();
    dic.Add("client_id", GlobalSetting.Instance.ClientId);
    dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); 
    dic.Add("response_type", "code id_token");
    dic.Add("scope", "openid profile basket orders locations marketing offline_access");
    dic.Add("redirect_uri", GlobalSetting.Instance.Callback);
    dic.Add("nonce", Guid.NewGuid().ToString("N"));
    dic.Add("code_challenge", CreateCodeChallenge());
    dic.Add("code_challenge_method", "S256");

    // Add CSRF token to protect against cross-site request forgery attacks.
    var currentCSRFToken = Guid.NewGuid().ToString("N");
    dic.Add("state", currentCSRFToken);

    var authorizeUri = authorizeRequest.Create(dic); 
    return authorizeUri;
}

Esse método cria o URI para o 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 móvel eShopOnContainers é reduzida com a implementação da extensão PKCE (Chave de Prova para Troca de Código) para OAuth. O PKCE protege o código de autorização de ser usado se 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.

O URI retornado é armazenado na propriedade LoginUrl da classe LoginViewModel. Quando a IsLogin propriedade se torna true, o WebView no LoginView torna-se visível. Os WebView dados associam sua Source propriedade à LoginUrl propriedade da classe e, portanto, fazem uma solicitação de entrada para IdentityServer quando a LoginUrl propriedade é definida como o ponto de extremidade de LoginViewModel autorização do IdentityServer. Quando o IdentityServer receber essa solicitação e o usuário não estiver autenticado, ele WebView será redirecionado para a página de logon configurada, que é mostrada na Figura 9-4.

Página de login exibida pelo WebView

Figura 9-4: Página de login exibida pelo WebView

Depois que o logon for concluído, o WebView será redirecionado para um URI de retorno. Essa navegação de WebView fará com que o método NavigateAsync na classe LoginViewModel seja executado, o que é mostrado no exemplo de código a seguir:

private async Task NavigateAsync(string url)  
{  
    ...  
    var authResponse = new AuthorizeResponse(url);  
    if (!string.IsNullOrWhiteSpace(authResponse.Code))  
    {  
        var userToken = await _identityService.GetTokenAsync(authResponse.Code);  
        string accessToken = userToken.AccessToken;  

        if (!string.IsNullOrWhiteSpace(accessToken))  
        {  
            Settings.AuthAccessToken = accessToken;  
            Settings.AuthIdToken = authResponse.IdentityToken;  

            await NavigationService.NavigateToAsync<MainViewModel>();  
            await NavigationService.RemoveLastFromBackStackAsync();  
        }  
    }  
    ...  
}

Esse método analisa a resposta de autenticação contida no URI de retorno e, desde que um código de autorização válido esteja presente, ele faz uma solicitação ao ponto de extremidade de token do IdentityServer, passando o código de autorização, o verificador de segredo PKCE e outros parâmetros necessários. O ponto de extremidade do token está em /connect/token 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.

Dica

Valide os URIs de retorno. Embora o aplicativo móvel eShopOnContainers não valide o URI de retorno, a prática recomendada é validar se o URI de retorno se refere a um local conhecido, para evitar ataques de redirecionamento aberto.

Se o ponto de extremidade de token receber um código de autorização válido e um verificador de segredo PKCE, ele responderá com um token de acesso, um de identidade e um de atualização. O token de acesso (que permite o acesso aos recursos da API) e o token de identidade são armazenados como configurações do aplicativo e a navegação na página é executada. Portanto, o efeito geral no aplicativo móvel eShopOnContainers é o seguinte: desde que os usuários consigam se autenticar com êxito com o IdentityServer, eles são navegados até a MainView página, que é exibida TabbedPage CatalogView como sua guia selecionada.

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

Observação

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

Saída

Quando o usuário toca no botão LOG OUT no ProfileView, a LogoutCommand classe ProfileViewModel é executada, que por sua vez executa o LogoutAsync método. Esse método executa a navegação de página para a página LoginView, passando uma instância LogoutParameter definida como um parâmetro true. Para obter mais informações sobre como passar parâmetros durante a navegação na página, consulte Passando parâmetros durante a navegação.

Quando uma exibição é criada e navegada para, o método InitializeAsync do modelo de exibição associado da exibição é executado, que executa o método Logout da classe LoginViewModel, que é mostrado no exemplo de código a seguir:

private void Logout()  
{  
    var authIdToken = Settings.AuthIdToken;  
    var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);  

    if (!string.IsNullOrEmpty(logoutRequest))  
    {  
        // Logout  
        LoginUrl = logoutRequest;  
    }  
    ...  
}

Esse método invoca o método CreateLogoutRequest na classe IdentityService, passando o token de identidade recuperado das configurações do aplicativo como um parâmetro. Para obter mais informações sobre as configurações do aplicativo, consulte Gerenciamento de configuração. O seguinte exemplo de código mostra o método CreateLogoutRequest:

public string CreateLogoutRequest(string token)  
{  
    ...  
    return string.Format("{0}?id_token_hint={1}&post_logout_redirect_uri={2}",   
        GlobalSetting.Instance.LogoutEndpoint,  
        token,  
        GlobalSetting.Instance.LogoutCallback);  
}

Esse método cria o URI para o ponto de extremidade da sessão final 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. Para obter mais informações sobre as configurações do usuário, confira Gerenciamento de Configurações.

O URI retornado é armazenado na propriedade LoginUrl da classe LoginViewModel. Enquanto a IsLogin propriedade é true, o WebView no LoginView é visível. Os WebView dados associam sua Source propriedade à LoginUrl propriedade da classe e, portanto, fazem uma solicitação de saída para IdentityServer quando a LoginUrl propriedade é definida como o ponto de extremidade da LoginViewModel sessão final do IdentityServer. Quando o IdentityServer recebe essa solicitação, desde que o usuário esteja conectado, ocorre a saída. A autenticação é controlada com um cookie gerenciado pelo middleware de autenticação correspondente de ASP.NET Core. Portanto, sair do IdentityServer remove o cookie de autenticação e envia um URI de redirecionamento pós-logout de volta ao cliente.

No aplicativo móvel, o WebView será redirecionado para o URI de redirecionamento de logout de postagem. Essa navegação de WebView fará com que o método NavigateAsync na classe LoginViewModel seja executado, o que é mostrado no exemplo de código a seguir:

private async Task NavigateAsync(string url)  
{  
    ...  
    Settings.AuthAccessToken = string.Empty;  
    Settings.AuthIdToken = string.Empty;  
    IsLogin = false;  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    ...  
}

Esse método limpa o token de identidade e o token de acesso das configurações do aplicativo e define a IsLogin propriedade como false, o que faz com que o WebView LoginView na página fique invisível. Por fim, a propriedade LoginUrl é definida como o URI do ponto de extremidade de autorização do IdentityServer, com os parâmetros necessários, em preparação para a próxima vez que o usuário iniciar uma entrada.

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

Observação

O eShopOnContainers também permite uma saída simulada quando o aplicativo está configurado para usar serviços fictícios 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, ASP.NET APIs Web principais 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 do acesso a uma rota MVC do ASP.NET Core pode ser obtida aplicando um atributo Authorize 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 class BasketController : Controller  
{  
    ...  
}

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

Observação

Os parâmetros podem ser especificados no Authorize atributo para restringir uma API a usuários específicos. Para obter mais informações, consulte Autorização.

O IdentityServer pode ser integrado ao fluxo de trabalho de autorização para que os tokens de acesso forneçam autorização de controle. Essa abordagem é mostrada na Figura 9-5.

Autorização por token de acesso

Figura 9-5: Autorização por token de acesso

O aplicativo móvel eShopOnContainers 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, consulte Configurando recursos de API.

Configurando o 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 ao ConfigureAuth método na classe do Startup aplicativo Web, que é invocado a Configure partir do método e é demonstrado no exemplo de código a seguir do aplicativo de referência eShopOnContainers:

protected virtual void ConfigureAuth(IApplicationBuilder app)  
{  
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");  
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions  
    {  
        Authority = identityUrl.ToString(),  
        ScopeName = "basket",  
        RequireHttpsMetadata = false  
    });  
} 

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 se o token é válido para ser usado com a API que o recebe. Portanto, navegar até o controlador de pedidos ou cesta retornará um código de status HTTP 401 (não autorizado), indicando que um token de acesso é necessário.

Observação

O middleware de autorização do IdentityServer deve ser adicionado ao pipeline de solicitação HTTP do aplicativo Web antes de adicionar o MVC com app.UseMvc() ou app.UseMvcWithDefaultRoute().

Fazendo 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:

var authToken = Settings.AuthAccessToken;  
Order = await _ordersService.GetOrderAsync(Convert.ToInt32(order.OrderNumber), authToken);

O token de acesso é armazenado como uma configuração de aplicativo e é recuperado do armazenamento específico da plataforma e incluído na chamada para o GetOrderAsync método na OrderService classe.

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:

var authToken = Settings.AuthAccessToken;  
await _basketService.UpdateBasketAsync(new CustomerBasket  
{  
    BuyerId = userInfo.UserId,   
    Items = BasketItems.ToList()  
}, authToken);

O token de acesso é recuperado do armazenamento específico da plataforma e incluído na chamada para o UpdateBasketAsync método na BasketService classe.

A RequestProvider classe, no aplicativo móvel eShopOnContainers, usa a HttpClient classe para fazer solicitações para as APIs RESTful expostas pelo aplicativo de referência eShopOnContainers. 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, conforme demonstrado no exemplo de HttpClient 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 Authorization valor do cabeçalho é 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 o recebe.

Para obter mais informações sobre como o aplicativo móvel eShopOnContainers faz solicitações da Web, consulte Acessando dados remotos.

Resumo

Há muitas abordagens para integrar autenticação e autorização em um Xamarin.Forms aplicativo que se comunica com um aplicativo Web MVC ASP.NET. O aplicativo móvel eShopOnContainers executa autenticação e autorização com um microsserviço de identidade em contêiner que usa o IdentityServer 4. 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 móvel solicita tokens de segurança do IdentityServer, seja para autenticar um usuário ou para 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.