Partilhar via


Autenticação e autorização do ASP.NET Core Blazor Hybrid

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Este artigo descreve o suporte do ASP.NET Core para a configuração e o gerenciamento de segurança e ASP.NET Core Identity em aplicativos Blazor Hybrid.

A autenticação em aplicativos Blazor Hybrid é tratada por bibliotecas de plataforma nativas, pois elas oferecem garantias de segurança aprimoradas que a área restrita do navegador não pode oferecer. A autenticação de aplicativos nativos usa um mecanismo específico do sistema operacional ou por meio de um protocolo federado, como OpenID Connect (OIDC). Siga as orientações para o provedor de identity que você selecionou para o aplicativo e, em seguida, integre ainda mais identity com Blazor usando as orientações neste artigo.

A integração da autenticação deve alcançar as seguintes metas para os componentes e serviços Razor:

  • Use as abstrações no pacote Microsoft.AspNetCore.Components.Authorization, como AuthorizeView.
  • Reaja a alterações no contexto de autenticação.
  • Credenciais de acesso provisionadas pela aplicação através do fornecedor identity, como tokens de acesso para executar chamadas à API autorizadas.

Após a adição de autenticação a um aplicativo .NET MAUI, WPF ou Windows Forms e os utilizadores conseguirem iniciar e encerrar sessão com êxito, integre a autenticação com Blazor de modo a tornar o utilizador autenticado disponível para os componentes e serviços de Razor. Execute as seguintes etapas:

.NET MAUI aplicativos usam a classe WebAuthenticator para iniciar fluxos de autenticação baseados em navegador que escutam um retorno de chamada para uma URL específica registrada no aplicativo.

Para obter orientações adicionais, consulte os seguintes recursos:

Os aplicativos do Windows Forms usam a plataforma Microsoft identity para integração com o Microsoft Entra (ME-ID) e o AAD B2C. Para obter mais informações, consulte Overview of the Microsoft Authentication Library (MSAL).

Criar um AuthenticationStateProvider personalizado sem atualizações de alteração do usuário

Se o aplicativo autenticar o usuário imediatamente após a inicialização do aplicativo e o usuário autenticado permanecer o mesmo durante todo o tempo de vida do aplicativo, as notificações de alteração do usuário não serão necessárias e o aplicativo fornecerá apenas informações sobre o usuário autenticado. Neste cenário, o utilizador inicia sessão na aplicação quando esta é aberta e a aplicação apresenta novamente o ecrã de início de sessão depois de o utilizador terminar sessão. O ExternalAuthStateProvider a seguir é um exemplo de implementação de um AuthenticationStateProvider personalizado para esse cenário de autenticação.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private readonly Task<AuthenticationState> authenticationState;

    public ExternalAuthStateProvider(AuthenticatedUser user) => 
        authenticationState = Task.FromResult(new AuthenticationState(user.Principal));

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        authenticationState;
}

public class AuthenticatedUser
{
    public ClaimsPrincipal Principal { get; set; } = new();
}

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione as abstrações Blazor e os serviços de autorização à coleção de serviços.
  • Crie a coleção de serviços.
  • Resolva o serviço AuthenticatedUser para definir a entidade de declarações do usuário autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.
  • Devolva o host construído.

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione namespaces para Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que retorna uma Microsoft.Maui.Hosting.MauiAppcompilada:

- return builder.Build();

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();

var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

return host;

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione os serviços de autorização e as abstrações Blazor à coleção de serviços.
  • Crie a coleção de serviços e adicione a coleção de serviços criada como um recurso à ResourceDictionarydo aplicativo.
  • Configure o serviço AuthenticatedUser para definir o principal de reivindicações do usuário autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.
  • Retorne o host compilado.

No construtor do MainWindow(MainWindow.xaml.cs), adicione espaços de nomes para Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que adiciona a coleção de serviços criada como um recurso ao ResourceDictionarydo aplicativo:

- Resources.Add("services", serviceCollection.BuildServiceProvider());

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);

var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione os serviços de autorização e abstrações Blazor ao conjunto de serviços.
  • Crie a coleção de serviços e adicione a coleção de serviços criada ao provedor de serviços do aplicativo.
  • Resolva o serviço AuthenticatedUser para definir a entidade de declarações do usuário autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.

No construtor do Form1(Form1.cs), adicione os namespaces de Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que define a coleção de serviços criada para o provedor de serviços do aplicativo:

- blazorWebView1.Services = services.BuildServiceProvider();

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;

var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Criar um AuthenticationStateProvider personalizado que inclua atualizações feitas pelo usuário

Para atualizar o usuário enquanto o aplicativo Blazor está em execução, chame NotifyAuthenticationStateChanged dentro da implementação AuthenticationStateProvider usando uma das seguintes abordagens:

Sinalizar uma atualização de autenticação de fora do BlazorWebView (Opção 1)

Um AuthenticationStateProvider personalizado pode usar um serviço global para sinalizar uma atualização de autenticação. Recomendamos que o serviço ofereça um evento ao qual o AuthenticationStateProvider possa subscrever, no qual o evento invoque NotifyAuthenticationStateChanged.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private AuthenticationState currentUser;

    public ExternalAuthStateProvider(ExternalAuthService service)
    {
        currentUser = new AuthenticationState(service.CurrentUser);

        service.UserChanged += (newUser) =>
        {
            currentUser = new AuthenticationState(newUser);
            NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
        };
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(currentUser);
}

public class ExternalAuthService
{
    public event Action<ClaimsPrincipal>? UserChanged;
    private ClaimsPrincipal? currentUser;

    public ClaimsPrincipal CurrentUser
    {
        get { return currentUser ?? new(); }
        set
        {
            currentUser = value;

            if (UserChanged is not null)
            {
                UserChanged(currentUser);
            }
        }
    }
}

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione um namespace para Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações de Blazor à coleção de serviços.

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();

No construtor de MainWindow(MainWindow.xaml.cs), adicione um namespace associado a Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações Blazor à coleção de serviços:

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();

No construtor de Form1(Form1.cs), adicione um namespace para Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações de Blazor à coleção de serviços:

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();

Em qualquer lugar onde a aplicação autentique um utilizador, resolva o serviço ExternalAuthService.

var authService = host.Services.GetRequiredService<ExternalAuthService>();

Execute seu código OpenID/MSAL personalizado para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes. O usuário autenticado (authenticatedUser no exemplo a seguir) é um novo ClaimsPrincipal baseado em um novo ClaimsIdentity.

Defina o usuário atual para o usuário autenticado:

authService.CurrentUser = authenticatedUser;

Uma alternativa à abordagem anterior é definir a identidade do usuário em System.Threading.Thread.CurrentPrincipal em vez de defini-la através de um serviço, o que evita o uso do contêiner de injeção de dependências.

public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(
            new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ?? 
                new ClaimsPrincipal(new ClaimsIdentity())));
}

Usando a abordagem alternativa, somente os serviços de autorização (AddAuthorizationCore) e CurrentThreadUserAuthenticationStateProvider (.TryAddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()) são adicionados à coleção de serviços.

Gerir a autenticação dentro do BlazorWebView (Opção 2)

Um AuthenticationStateProvider personalizado pode incluir métodos adicionais para efetuar login e logout e atualizar o utilizador.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(new AuthenticationState(currentUser));

    public Task LogInAsync()
    {
        var loginTask = LogInAsyncCore();
        NotifyAuthenticationStateChanged(loginTask);

        return loginTask;

        async Task<AuthenticationState> LogInAsyncCore()
        {
            var user = await LoginWithExternalProviderAsync();
            currentUser = user;

            return new AuthenticationState(currentUser);
        }
    }

    private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
    {
        /*
            Provide OpenID/MSAL code to authenticate the user. See your identity 
            provider's documentation for details.

            Return a new ClaimsPrincipal based on a new ClaimsIdentity.
        */
        var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());

        return Task.FromResult(authenticatedUser);
    }

    public void Logout()
    {
        currentUser = new ClaimsPrincipal(new ClaimsIdentity());
        NotifyAuthenticationStateChanged(
            Task.FromResult(new AuthenticationState(currentUser)));
    }
}

No exemplo anterior:

  • A chamada para LogInAsyncCore aciona o processo de login.
  • A chamada para NotifyAuthenticationStateChanged notifica que uma atualização está em andamento, o que permite que o aplicativo forneça uma interface do usuário temporária durante o processo de login ou logout.
  • O retorno loginTask retorna a tarefa para que o componente que disparou o logon possa aguardar e reagir após a conclusão da tarefa.
  • O método LoginWithExternalProviderAsync é implementado pelo desenvolvedor para fazer login no usuário com o SDK do provedor de identity. Para obter mais informações, consulte a documentação do seu provedor de identity. O usuário autenticado (authenticatedUser) é um novo ClaimsPrincipal baseado em um novo ClaimsIdentity.

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione os serviços de autorização e a abstração Blazor à coleção de serviços:

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

No construtor de MainWindow(MainWindow.xaml.cs), adicione os serviços de autorização e a abstração Blazor à coleção de serviços.

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

No construtor de Form1(emForm1.cs), adicione os serviços de autorização e a abstração de Blazor à coleção de serviços.

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

O seguinte componente LoginComponent demonstra como fazer login de um utilizador. Em um aplicativo típico, o componente LoginComponent só é mostrado em um componente pai se o usuário não estiver conectado ao aplicativo.

Shared/LoginComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Login">Log in</button>

@code
{
    public async Task Login()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();
    }
}

O componente LogoutComponent a seguir demonstra como fazer logout de um usuário. Em um aplicativo típico, o componente LogoutComponent só é mostrado em um componente pai se o usuário estiver conectado ao aplicativo.

Shared/LogoutComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Logout">Log out</button>

@code
{
    public async Task Logout()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .Logout();
    }
}

Acesso a outras informações de autenticação

Blazor não define uma abstração para lidar com outras credenciais, como tokens de acesso a serem usados para solicitações HTTP para APIs da Web. Recomendamos seguir as orientações do provedor de identity para gerenciar as credenciais do usuário com as primitivas fornecidas pelo SDK do provedor de identity.

É comum que os SDKs do provedor de identity usem um armazenamento de token para credenciais de usuário armazenadas no dispositivo. Se a primitiva do repositório de tokens do SDK for adicionada ao contêiner de serviço, consuma a primitiva do SDK dentro do aplicativo.

A estrutura Blazor não está ciente das credenciais de autenticação de um usuário e não interage com as credenciais de forma alguma, portanto, o código do aplicativo é livre para seguir qualquer abordagem que você considere mais conveniente. No entanto, siga as orientações gerais de segurança na próxima seção, Outras considerações de segurança de autenticação, ao implementar o código de autenticação em um aplicativo.

Outras considerações de segurança de autenticação

O processo de autenticação é externo ao Blazore recomendamos que os desenvolvedores acessem as orientações do provedor de identity para obter orientações de segurança adicionais.

Ao implementar a autenticação:

  • Evite a autenticação no contexto do Web View. Por exemplo, evite usar uma biblioteca OAuth JavaScript para executar o fluxo de autenticação. Em um aplicativo de página única, os tokens de autenticação não estão ocultos em JavaScript e podem ser facilmente descobertos por usuários mal-intencionados e usados para fins nefastos. Os aplicativos nativos não sofrem esse risco porque os aplicativos nativos só são capazes de obter tokens fora do contexto do navegador, o que significa que scripts de terceiros não podem roubar os tokens e comprometer o aplicativo.
  • Evite implementar o fluxo de trabalho de autenticação por conta própria. Na maioria dos casos, as bibliotecas de plataforma lidam com segurança com o fluxo de trabalho de autenticação, usando o navegador do sistema em vez de usar um Web View personalizado que pode ser sequestrado.
  • Evite usar o controle de Web View da plataforma para realizar a autenticação. Em vez disso, confie no navegador do sistema sempre que possível.
  • Evite passar os tokens para o contexto do documento (JavaScript). Em algumas situações, uma biblioteca JavaScript dentro do documento é necessária para executar uma chamada autorizada para um serviço externo. Em vez de disponibilizar o token para JavaScript através da interoperabilidade JS:
    • Forneça um token temporário gerado para a biblioteca e utilize-o dentro do Web View.
    • Intercetar a solicitação de saída da rede no código.
    • Substitua o token temporário pelo token real e confirme se o destino da solicitação é válido.

Recursos adicionais

A autenticação em aplicativos Blazor Hybrid é tratada por bibliotecas de plataforma nativas, pois elas oferecem garantias de segurança aprimoradas que a área restrita do navegador não pode oferecer. A autenticação de aplicativos nativos usa um mecanismo específico do sistema operacional ou por meio de um protocolo federado, como OpenID Connect (OIDC). Siga as orientações para o provedor de identity que você selecionou para o aplicativo e, em seguida, integre ainda mais identity com Blazor usando as orientações neste artigo.

O processo de integração da autenticação deve atingir as seguintes metas para os componentes e serviços Razor.

  • Use as abstrações no pacote Microsoft.AspNetCore.Components.Authorization, como AuthorizeView.
  • Reaja a alterações no contexto de autenticação.
  • Credenciais de acesso fornecidas pela aplicação a partir do fornecedor identity, como tokens de acesso para executar chamadas de API autorizadas.

Depois de ser adicionada a autenticação a um aplicativo .NET MAUI, WPF ou Windows Forms, e os usuários conseguirem fazer login e logout com êxito, integre a autenticação com Blazor para disponibilizar o usuário autenticado aos componentes e serviços Razor. Execute as seguintes etapas:

.NET MAUI aplicativos usam a classe WebAuthenticator para iniciar fluxos de autenticação baseados em navegador que escutam um retorno de chamada para uma URL específica registrada no aplicativo.

Para obter orientações adicionais, consulte os seguintes recursos:

Os aplicativos do Windows Forms usam a plataforma Microsoft identity para integração com o Microsoft Entra (ME-ID) e o AAD B2C. Para obter mais informações, consulte Overview of the Microsoft Authentication Library (MSAL).

Criar um AuthenticationStateProvider personalizado sem atualizações de alterações feitas pelo usuário

Se o aplicativo autenticar o usuário imediatamente após a inicialização do aplicativo e o usuário autenticado permanecer o mesmo durante todo o tempo de vida do aplicativo, as notificações de alteração do usuário não serão necessárias e o aplicativo fornecerá apenas informações sobre o usuário autenticado. Neste cenário, o utilizador inicia sessão na aplicação quando esta é aberta e a aplicação apresenta novamente o ecrã de início de sessão depois de o utilizador terminar sessão. O ExternalAuthStateProvider a seguir é um exemplo de implementação de um AuthenticationStateProvider personalizado para esse cenário de autenticação.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private readonly Task<AuthenticationState> authenticationState;

    public ExternalAuthStateProvider(AuthenticatedUser user) => 
        authenticationState = Task.FromResult(new AuthenticationState(user.Principal));

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        authenticationState;
}

public class AuthenticatedUser
{
    public ClaimsPrincipal Principal { get; set; } = new();
}

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione os serviços de autorização e as abstrações de Blazor à coleção de serviços.
  • Crie a coleção de serviços.
  • Configure o serviço AuthenticatedUser para definir as informações de declaração do utilizador autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.
  • Devolva o host construído.

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione namespaces para Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que retorna uma Microsoft.Maui.Hosting.MauiAppcompilada:

- return builder.Build();

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();

var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

return host;

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione os serviços de autorização e as abstrações Blazor à coleção de serviços.
  • Crie a coleção de serviços e adicione a coleção de serviços criada como um recurso à ResourceDictionarydo aplicativo.
  • Resolva o serviço AuthenticatedUser para definir a entidade de declarações do usuário autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.
  • Retorne o host construído.

No construtor do MainWindow's (MainWindow.xaml.cs), adicione namespaces para Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que adiciona a coleção de serviços criada como um recurso ao ResourceDictionarydo aplicativo:

- Resources.Add("services", serviceCollection.BuildServiceProvider());

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);

var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

As etapas a seguir descrevem como:

  • Adicione namespaces necessários.
  • Adicione os serviços de autorização e as abstrações Blazor à coleção de serviços.
  • Crie a coleção de serviços e adicione a coleção de serviços criada ao provedor de serviços do aplicativo.
  • Resolva o serviço AuthenticatedUser para definir a entidade de declarações do usuário autenticado. Consulte a documentação do seu fornecedor de identity para obter detalhes.

No construtor de Form1(Form1.cs), adicione os namespaces de Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Remova a seguinte linha de código que define a coleção de serviços criada para o provedor de serviços do aplicativo:

- blazorWebView1.Services = services.BuildServiceProvider();

Substitua a linha de código anterior pelo código a seguir. Adicione código OpenID/MSAL para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes.

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;

var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Criar um AuthenticationStateProvider personalizado com alterações feitas pelo utilizador

Para atualizar o usuário enquanto o aplicativo Blazor está em execução, chame NotifyAuthenticationStateChanged dentro da implementação AuthenticationStateProvider usando uma das seguintes abordagens:

Sinalizar uma atualização de autenticação de fora do BlazorWebView (Opção 1)

Um AuthenticationStateProvider personalizado pode usar um serviço global para sinalizar uma atualização de autenticação. Recomendamos que o serviço ofereça um evento a que o AuthenticationStateProvider possa subscrever, em que o evento invoque NotifyAuthenticationStateChanged.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private AuthenticationState currentUser;

    public ExternalAuthStateProvider(ExternalAuthService service)
    {
        currentUser = new AuthenticationState(service.CurrentUser);

        service.UserChanged += (newUser) =>
        {
            currentUser = new AuthenticationState(newUser);
            NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
        };
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(currentUser);
}

public class ExternalAuthService
{
    public event Action<ClaimsPrincipal>? UserChanged;
    private ClaimsPrincipal? currentUser;

    public ClaimsPrincipal CurrentUser
    {
        get { return currentUser ?? new(); }
        set
        {
            currentUser = value;

            if (UserChanged is not null)
            {
                UserChanged(currentUser);
            }
        }
    }
}

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione um namespace para Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações de Blazor à coleção de serviços.

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();

No construtor de MainWindow(MainWindow.xaml.cs), adicione um namespace para Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações Blazor à coleção de serviços:

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();

No construtor do Form1's (Form1.cs), adicione um namespace para Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Adicione os serviços de autorização e as abstrações de Blazor à coleção de serviços.

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();

Onde quer que a aplicação autentique um utilizador, resolva o serviço ExternalAuthService.

var authService = host.Services.GetRequiredService<ExternalAuthService>();

Execute seu código OpenID/MSAL personalizado para autenticar o usuário. Consulte a documentação do seu fornecedor de identity para obter detalhes. O usuário autenticado (authenticatedUser no exemplo a seguir) é um novo ClaimsPrincipal baseado em um novo ClaimsIdentity.

Defina o usuário atual para o usuário autenticado:

authService.CurrentUser = authenticatedUser;

Uma alternativa à abordagem anterior é definir o principal do usuário no System.Threading.Thread.CurrentPrincipal em vez de defini-lo por meio de um serviço, o que evita o uso do contêiner de injeção de dependência.

public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(
            new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ?? 
                new ClaimsPrincipal(new ClaimsIdentity())));
}

Usando a abordagem alternativa, somente os serviços de autorização (AddAuthorizationCore) e CurrentThreadUserAuthenticationStateProvider (.AddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()) são adicionados à coleção de serviços.

Gerir autenticação dentro do BlazorWebView (Opção 2)

Um AuthenticationStateProvider personalizado pode incluir métodos adicionais para ativar o início e término de sessão, além de atualizar o utilizador.

Observação

O AuthenticationStateProvider personalizado a seguir não declara um namespace para tornar o exemplo de código aplicável a qualquer aplicativo Blazor Hybrid. No entanto, uma prática recomendada é fornecer o namespace do seu aplicativo quando você implementa o exemplo em um aplicativo de produção.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(new AuthenticationState(currentUser));

    public Task LogInAsync()
    {
        var loginTask = LogInAsyncCore();
        NotifyAuthenticationStateChanged(loginTask);

        return loginTask;

        async Task<AuthenticationState> LogInAsyncCore()
        {
            var user = await LoginWithExternalProviderAsync();
            currentUser = user;

            return new AuthenticationState(currentUser);
        }
    }

    private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
    {
        /*
            Provide OpenID/MSAL code to authenticate the user. See your identity 
            provider's documentation for details.

            Return a new ClaimsPrincipal based on a new ClaimsIdentity.
        */
        var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());

        return Task.FromResult(authenticatedUser);
    }

    public void Logout()
    {
        currentUser = new ClaimsPrincipal(new ClaimsIdentity());
        NotifyAuthenticationStateChanged(
            Task.FromResult(new AuthenticationState(currentUser)));
    }
}

No exemplo anterior:

  • A chamada para LogInAsyncCore aciona o processo de login.
  • A chamada para NotifyAuthenticationStateChanged notifica que uma atualização está em andamento, o que permite que o aplicativo forneça uma interface do usuário temporária durante o processo de login ou logout.
  • O retorno loginTask retorna a tarefa para que o componente que disparou o logon possa aguardar e reagir após a conclusão da tarefa.
  • O método LoginWithExternalProviderAsync é implementado pelo desenvolvedor para fazer login no usuário com o SDK do provedor de identity. Para obter mais informações, consulte a documentação do seu provedor de identity. O usuário autenticado (authenticatedUser) é um novo ClaimsPrincipal baseado em um novo ClaimsIdentity.

No método MauiProgram.CreateMauiApp de MauiProgram.cs, adicione os serviços de autorização e a abstração Blazor à coleção de serviços:

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

No construtor de MainWindow(MainWindow.xaml.cs), adicione os serviços de autorização e a abstração Blazor à coleção de serviços:

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

No construtor de Form1(Form1.cs), adicione os serviços de autorização e a abstração Blazor ao conjunto de serviços.

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

O componente LoginComponent seguinte demonstra como iniciar sessão do utilizador. Em um aplicativo típico, o componente LoginComponent só é mostrado em um componente pai se o usuário não estiver conectado ao aplicativo.

Shared/LoginComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Login">Log in</button>

@code
{
    public async Task Login()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();
    }
}

O componente LogoutComponent a seguir demonstra como fazer logout de um usuário. Em um aplicativo típico, o componente LogoutComponent só é mostrado em um componente pai se o usuário estiver conectado ao aplicativo.

Shared/LogoutComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Logout">Log out</button>

@code
{
    public async Task Logout()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .Logout();
    }
}

Acesso a outras informações de autenticação

Blazor não define uma abstração para lidar com outras credenciais, como tokens de acesso a serem usados para solicitações HTTP para APIs da Web. Recomendamos seguir as orientações do provedor de identity para gerenciar as credenciais do usuário com as primitivas fornecidas pelo SDK do provedor de identity.

É comum que os SDKs do provedor de identity usem um armazenamento de token para credenciais de usuário armazenadas no dispositivo. Se a primitiva do repositório de tokens do SDK for adicionada ao contentor de serviço, utilize a primitiva do SDK dentro da aplicação.

A estrutura Blazor não está ciente das credenciais de autenticação de um usuário e não interage com as credenciais de forma alguma, portanto, o código do aplicativo é livre para seguir qualquer abordagem que você considere mais conveniente. No entanto, siga as orientações gerais de segurança na próxima seção, Outras considerações de segurança de autenticação, ao implementar o código de autenticação em um aplicativo.

Outras considerações de segurança de autenticação

O processo de autenticação é externo ao Blazore recomendamos que os desenvolvedores acessem as orientações do provedor de identity para obter orientações de segurança adicionais.

Ao implementar a autenticação:

  • Evite a autenticação no contexto do Web View. Por exemplo, evite usar uma biblioteca OAuth JavaScript para executar o fluxo de autenticação. Em um aplicativo de página única, os tokens de autenticação não estão ocultos em JavaScript e podem ser facilmente descobertos por usuários mal-intencionados e usados para fins nefastos. Os aplicativos nativos não sofrem esse risco porque os aplicativos nativos só são capazes de obter tokens fora do contexto do navegador, o que significa que scripts de terceiros não podem roubar os tokens e comprometer o aplicativo.
  • Evite implementar o fluxo de trabalho de autenticação por conta própria. Na maioria dos casos, as bibliotecas de plataforma lidam com segurança com o fluxo de trabalho de autenticação, usando o navegador do sistema em vez de usar um Web View personalizado que pode ser sequestrado.
  • Evite usar o controle de Web View da plataforma para realizar a autenticação. Em vez disso, confie no navegador do sistema sempre que possível.
  • Evite passar os tokens para o contexto do documento (JavaScript). Em algumas situações, uma biblioteca JavaScript dentro do documento é necessária para executar uma chamada autorizada para um serviço externo. Em vez de disponibilizar o token para JavaScript por meio de interoperabilidade JS:
    • Forneça um token temporário gerado para a biblioteca e dentro do Web View.
    • Intercepte a solicitação de rede de saída no código.
    • Substitua o token temporário pelo token real e confirme se o destino da solicitação é válido.

Recursos adicionais