Proteja o ASP.NET Core Blazor WebAssembly com o ASP.NET Core Identity
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.
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.
Os aplicativos Blazor WebAssembly autônomos podem ser protegidos com ASP.NET Identity Core seguindo as orientações deste artigo.
Pontos de extremidade para registro, login e logout
Em vez de usar o UI padrão fornecido pelo ASP.NET Core Identity para aplicativos SPA e Blazor, que se baseia em Razor Pages, chame MapIdentityApi numa API backend para adicionar endpoints de API JSON para registar e autenticar utilizadores com ASP.NET Core Identity. Identity endpoints da API também suportam recursos avançados, como autenticação de dois fatores e confirmação de e-mail.
No cliente, ligue para o endpoint /register
para registar um utilizador com o seu e-mail e senha:
var result = await _httpClient.PostAsJsonAsync(
"register", new
{
email,
password
});
No cliente, inicie sessão num utilizador com autenticação cookie usando o endpoint /login
com a cadeia de consulta useCookies
definida como true
:
var result = await _httpClient.PostAsJsonAsync(
"login?useCookies=true", new
{
email,
password
});
A API do servidor backend estabelece a autenticação cookie com uma chamada para AddIdentityCookies no configurador de autenticação.
builder.Services
.AddAuthentication(IdentityConstants.ApplicationScheme)
.AddIdentityCookies();
Autenticação de token
Para cenários nativos e móveis em que alguns clientes não suportam cookies, a API de login fornece um parâmetro para solicitar tokens.
Advertência
Recomendamos o uso de cookies para aplicativos baseados em navegador em vez de tokens, pois o navegador lida com cookies sem expô-los ao JavaScript. Se você optar por usar segurança baseada em tokens em aplicativos Web, será responsável por garantir que os tokens sejam mantidos seguros.
É emitido um token personalizado (que é propriedade da plataforma ASP.NET Core Identity) que pode ser usado para autenticar solicitações subsequentes. O token deve ser passado no cabeçalho Authorization
como um token de portador. Um token de atualização também é fornecido. Esse token permite que o aplicativo solicite um novo token quando o antigo expirar sem forçar o usuário a fazer login novamente.
Os tokens não são JSON Web Tokens (JWTs) padrão. O uso de tokens personalizados é intencional, pois a API de Identity interna destina-se principalmente a cenários simples. A opção de token não se destina a ser um provedor de serviços de identity ou servidor de token com todos os recursos, mas sim uma alternativa à opção cookie para clientes que não podem usar cookies.
As diretrizes a seguir iniciam o processo de implementação da autenticação baseada em token com a API de login. É necessário um código personalizado para concluir a implementação. Para obter mais informações, consulte Usar Identity para proteger um back-end de API Web para SPAs.
Em vez de a API do servidor back-end estabelecer a autenticação cookie com uma chamada para AddIdentityCookies no construtor de autenticação, a API do servidor configura a autenticação com token bearer utilizando o método de extensão AddBearerToken. Especifique o esquema para tokens de autenticação de portador com IdentityConstants.BearerScheme.
No Backend/Program.cs
, altere os serviços de autenticação e a configuração para o seguinte:
builder.Services
.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme);
No BlazorWasmAuth/Identity/CookieAuthenticationStateProvider.cs
, remova o parâmetro de cadeia de caracteres de consulta useCookies
no método LoginAsync
do CookieAuthenticationStateProvider
:
- login?useCookies=true
+ login
Neste ponto, você deve fornecer código personalizado para analisar o AccessTokenResponse no cliente e gerenciar os tokens de acesso e atualização. Para obter mais informações, consulte Usar Identity para proteger um back-end de API Web para SPAs.
Cenários Identity adicionais
Cenários abrangidos pelo conjunto de documentação Blazor:
- Confirmação de conta, gerenciamento de senhas e códigos de recuperação
- Autenticação de dois fatores (2FA) com um aplicativo autenticador TOTP
Para obter informações sobre cenários de Identity adicionais fornecidos pela API, consulte Usar Identity para proteger um back-end de API da Web para SPAs:
- Proteger os pontos finais selecionados
- Gestão de informações do utilizador
Use fluxos de autenticação seguros para manter dados e credenciais confidenciais
Advertência
Não armazene segredos de aplicativos, cadeias de conexão, credenciais, senhas, números de identificação pessoal (PINs), código C#/.NET privado ou chaves/tokens privados no código do lado do cliente, que é sempre inseguro. Em ambientes de teste/preparação e produção, o código Blazor do lado do servidor e as APIs da Web devem usar fluxos de autenticação seguros que evitem a manutenção de credenciais no código do projeto ou nos arquivos de configuração. Fora dos testes de desenvolvimento local, recomendamos evitar o uso de variáveis de ambiente para armazenar dados confidenciais, pois as variáveis de ambiente não são a abordagem mais segura. Para testes de desenvolvimento local, a ferramenta Secret Manager é recomendada para proteger dados confidenciais. Para obter mais informações, consulte Manter com segurança dados confidenciais e credenciais.
Aplicativos de exemplo
Neste artigo, os aplicativos de exemplo servem como referência para aplicativos Blazor WebAssembly autônomos que acessam ASP.NET Core Identity por meio de uma API Web de back-end. A demonstração inclui dois aplicativos:
-
Backend
: Uma aplicação de API Web backend que mantém um repositório de utilizadores identity para ASP.NET Core Identity. -
BlazorWasmAuth
: Um aplicativo de front-end Blazor WebAssembly autônomo com autenticação de usuário.
Acesse os aplicativos de exemplo através da pasta da versão mais recente a partir da raiz do repositório com o link a seguir. Os exemplos são fornecidos para o .NET 8 ou posterior. Consulte o arquivo README
na pasta BlazorWebAssemblyStandaloneWithIdentity
para obter etapas sobre como executar os aplicativos de exemplo.
Ver ou baixar código de exemplo (como descarregar)
Pacotes e código de aplicativos de API de back-end Web
O aplicativo de API Web de back-end mantém um repositório de identity de usuário para ASP.NET Core Identity.
Pacotes
O aplicativo usa os seguintes pacotes NuGet:
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.InMemory
NSwag.AspNetCore
Se o seu aplicativo for usar um provedor de banco de dados EF Core diferente do provedor na memória, não crie uma referência de pacote em seu aplicativo para Microsoft.EntityFrameworkCore.InMemory
.
No arquivo de projeto da aplicação (.csproj
), a globalização invariante é configurada.
Exemplo de código do aplicativo
Configurações do aplicativo configurar URLs de back-end e frontend:
-
Backend
app (BackendUrl
):https://localhost:7211
-
BlazorWasmAuth
app (FrontendUrl
):https://localhost:7171
O arquivo Backend.http
pode ser usado para testar a solicitação de dados meteorológicos. Observe que o aplicativo BlazorWasmAuth
deve estar em execução para testar o ponto de extremidade e o ponto de extremidade é codificado no arquivo. Para obter mais informações, consulte Usar arquivos .http no Visual Studio 2022.
A seguinte instalação e configuração podem ser encontradas no arquivo Program
do aplicativo.
Utilizador identity com autenticação cookie é adicionado chamando AddAuthentication e AddIdentityCookies. Os serviços para verificações de autorização são adicionados por uma chamada para AddAuthorizationBuilder.
Recomendado apenas para demonstrações, o aplicativo usa o EF Core provedor de banco de dados na memória para o registro de contexto do banco de dados (AddDbContext). O provedor de banco de dados na memória facilita a reinicialização do aplicativo e o teste dos fluxos de usuário de registro e login. Cada execução começa com um novo banco de dados, mas a aplicação inclui código de demonstração de propagação de utilizadores de teste , que é descrito mais adiante neste artigo. Se o banco de dados for alterado para SQLite, os usuários serão salvos entre as sessões, mas o banco de dados deverá ser criado por meio de migrações
Observação
†O tutorial de introdução ao EF Core usa comandos do PowerShell para executar migrações de banco de dados ao usar o Visual Studio. Uma abordagem alternativa no Visual Studio é usar a interface do usuário do Connected Services:
No Explorador de Soluções, faça duplo clique em Serviços Conectados. Em Service Dependencies>SQL Server Express LocalDB, selecione as reticências (...
) seguidas por Adicionar migração para criar uma migração ou Atualizar banco de dados para atualizar o banco de dados.
Configure Identity para usar a base de dados EF Core e expor os endpoints Identity através das chamadas para AddIdentityCore, AddEntityFrameworkStorese AddApiEndpoints.
Uma política de Cross-Origin Resource Sharing (CORS) é estabelecida para permitir solicitações dos aplicativos frontend e backend. As URLs de fallback são configuradas para a política CORS se as configurações do aplicativo não forneçam:
-
Backend
app (BackendUrl
):https://localhost:5001
-
BlazorWasmAuth
app (FrontendUrl
):https://localhost:5002
Serviços e endpoints para Swagger/OpenAPI estão incluídos para a documentação da API web e testes de desenvolvimento. Para obter mais informações sobre o NSwag, consulte Introdução ao NSwag e ao ASP.NET Core.
As declarações de função de usuário são enviadas de um de API mínima de
As rotas são mapeadas para os endpoints Identity ao chamar MapIdentityApi<AppUser>()
.
Um ponto de extremidade de logout (/Logout
) é configurado no pipeline de middleware para terminar a sessão dos utilizadores.
Para proteger um endpoint, adicione o método de extensão RequireAuthorization à definição de rota. Para um controlador, adicione o atributo [Authorize]
ao controlador ou ação.
Para obter mais informações sobre padrões básicos para inicialização e configuração de uma instância DbContext, consulte DbContext Lifetime, Configuration, and Initialization na documentação do EF Core.
Frontend autónomo Blazor WebAssembly pacotes de aplicações e código
Um aplicativo frontend Blazor WebAssembly autônomo demonstra a autenticação e a autorização do usuário para acessar uma página da Web privada.
Pacotes
O aplicativo usa os seguintes pacotes NuGet:
Microsoft.AspNetCore.Components.WebAssembly.Authentication
Microsoft.Extensions.Http
Microsoft.AspNetCore.Components.WebAssembly
Microsoft.AspNetCore.Components.WebAssembly.DevServer
Exemplo de código do aplicativo
A pasta Models
contém os modelos do aplicativo:
-
FormResult
(Identity/Models/FormResult.cs
): Resposta para login e registro. -
UserInfo
(Identity/Models/UserInfo.cs
): Informações do utilizador do endpoint de identity para estabelecer reivindicações.
A interface IAccountManagement
(Identity/CookieHandler.cs
) fornece serviços de gerenciamento de contas.
A classe CookieAuthenticationStateProvider
(Identity/CookieAuthenticationStateProvider.cs
) manipula o estado para autenticação baseada em cookiee fornece implementações de serviço de gerenciamento de conta descritas pela interface IAccountManagement
. O método LoginAsync
habilita explicitamente a autenticação cookie por meio do valor da cadeia de caracteres de consulta useCookies
de true
. A classe também gerencia a criação de declarações de função para usuários autenticados.
A classe CookieHandler
(Identity/CookieHandler.cs
) garante que as credenciais cookie sejam enviadas com cada solicitação para a API web de back-end, que processa Identity e mantém o armazenamento de dados Identity.
O wwwroot/appsettings.file
fornece endereços de URL para o backend e frontend.
O componente App
expõe o estado de autenticação como um parâmetro em cascata. Para obter mais informações, consulte ASP.NET Core Blazor authentication and authorization.
Os componentes MainLayout
e NavMenu
usam o componente AuthorizeView
para exibir o conteúdo seletivamente com base no estado de autenticação do utilizador.
Os seguintes componentes lidam com tarefas comuns de autenticação de utilizador, utilizando os serviços IAccountManagement
.
-
Register
componente (Components/Identity/Register.razor
) -
Login
componente (Components/Identity/Login.razor
) -
Logout
componente (Components/Identity/Logout.razor
)
O componente PrivatePage
(Components/Pages/PrivatePage.razor
) requer autenticação e mostra as declarações do usuário.
Os serviços e a configuração são fornecidos no arquivo Program
(Program.cs
):
- O manipulador de cookie está registrado como um serviço com escopo.
- Os serviços de autorização são registados.
- O fornecedor de estado de autenticação personalizada é registado como um serviço com alcance limitado.
- A interface de gestão de conta (
IAccountManagement
) está registada. - A URL do host base é configurada para uma instância de cliente HTTP registrada.
- A URL do back-end base é configurada para uma instância de cliente HTTP registrada que é usada para interações com autenticação com a API web do back-end. O cliente HTTP usa o manipulador de cookie para garantir que cookie credenciais sejam enviadas com cada solicitação.
Chame AuthenticationStateProvider.NotifyAuthenticationStateChanged quando o estado de autenticação do usuário mudar. Para obter um exemplo, consulte os métodos LoginAsync
e LogoutAsync
da classe CookieAuthenticationStateProvider
(Identity/CookieAuthenticationStateProvider.cs
).
Advertência
O componente AuthorizeView exibe seletivamente o conteúdo da interface do usuário, dependendo se o usuário está autorizado. Todo o conteúdo dentro de um aplicativo Blazor WebAssembly colocado em um componente AuthorizeView é detetável sem autenticação, portanto, o conteúdo confidencial deve ser obtido de uma API da Web baseada em servidor de back-end depois que a autenticação for bem-sucedida. Para obter mais informações, consulte os seguintes recursos:
Demonstração de inicialização do utilizador de teste
A classe SeedData
(SeedData.cs
) demonstra como criar usuários de teste para desenvolvimento. O usuário de teste, chamado Leela, entra no aplicativo com o endereço de e-mail leela@contoso.com
. A senha do usuário está definida como Passw0rd!
. Leela recebe os perfis Administrator
e Manager
para autorização, o que permite que o utilizador aceda à página do gerente em /private-manager-page
, mas não à página do editor em /private-editor-page
.
Advertência
Nunca permita que o código de usuário de teste seja executado em um ambiente de produção.
SeedData.InitializeAsync
só é chamado no ambiente Development
no arquivo Program
:
if (builder.Environment.IsDevelopment())
{
await using var scope = app.Services.CreateAsyncScope();
await SeedData.InitializeAsync(scope.ServiceProvider);
}
Funções
As declarações de funções não são enviadas de volta a partir do ponto de extremidade manage/info
, para criar declarações de utilizador para os utilizadores da aplicação BlazorWasmAuth
. As declarações de função são gerenciadas independentemente por meio de uma solicitação separada no método GetAuthenticationStateAsync
da classe CookieAuthenticationStateProvider
(Identity/CookieAuthenticationStateProvider.cs
) depois que o usuário é autenticado no projeto Backend
.
No CookieAuthenticationStateProvider
, um pedido de funções é feito ao endpoint /roles
do projeto de API do servidor Backend
. A resposta é lida numa string através da chamada ReadAsStringAsync().
JsonSerializer.Deserialize desserializa a cadeia de caracteres em uma matriz de RoleClaim
personalizada. Finalmente, as declarações são adicionadas à coleção de declarações do usuário.
No arquivo de
O endpoint das funções requer autorização ao chamar RequireAuthorization. Se decidir não usar APIs mínimas em favor de controladores para os pontos finais seguros da API do servidor, certifique-se de definir o atributo [Authorize]
nos controladores ou ações.
Hospedagem entre domínios (configuração do mesmo site)
Os aplicativos de exemplo são configurados para hospedar ambos os aplicativos no mesmo domínio. Se hospitares a aplicação Backend
num domínio diferente do da aplicação BlazorWasmAuth
, descomenta o código que configura o cookie (ConfigureApplicationCookie) no ficheiro Backend
da aplicação Program
. Os valores padrão são:
- Modo mesmo site: SameSiteMode.Lax
- Política de segurança: CookieSecurePolicy.SameAsRequest
Altere os valores para:
- Modo mesmo site: SameSiteMode.None
- Política de segurança: CookieSecurePolicy.Always
- options.Cookie.SameSite = SameSiteMode.Lax;
- options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
+ options.Cookie.SameSite = SameSiteMode.None;
+ options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
Para obter mais informações sobre as configurações de cookie do mesmo site, consulte os seguintes recursos:
-
Set-Cookie:
SameSite=<samesite-value>
(documentação MDN) - Cookies: Mecanismo de Gerenciamento de Estado HTTP (RFC Draft 6265, Seção 4.1)
Suporte antifalsificação
Apenas o endpoint de logout (/logout
) na aplicação Backend
requer atenção para mitigar a ameaça de CSRF (Cross-Site Request Forgery) .
O endpoint de logout verifica a existência de um corpo vazio para prevenir ataques CSRF. Ao exigir um corpo, a solicitação deve ser feita a partir de JavaScript, que é a única maneira de acessar a autenticação cookie. O endpoint de logout não pode ser acessado por um formulário baseado em POST. Isso impede que um site mal-intencionado faça logout do usuário.
Além disso, o ponto final é protegido por autorização (RequireAuthorization) para impedir o acesso anónimo.
Basta que a aplicação cliente BlazorWasmAuth
passe um objeto vazio {}
no corpo da solicitação.
Fora do ponto de extremidade de logout, de mitigação antifalsificação só é necessária ao enviar dados de formulário para o servidor codificado como application/x-www-form-urlencoded
, multipart/form-data
ou text/plain
.
Blazor gerencia a mitigação de CSRF para formulários na maioria dos casos. Para obter mais informações, consulte Blazor de autenticação e autorização do Core e ASP.NET visão geral dos formulários Core Blazor.
Solicitações para outros endpoints de servidor API (API web) com conteúdo codificado em application/json
e CORS habilitado, não exigem proteção CSRF. É por isso que nenhuma proteção CSRF é necessária para o ponto de extremidade de processamento de dados (Backend
) do aplicativo /data-processing
. O endpoint de roles (/roles
) não necessita de proteção CSRF porque é um endpoint GET que não modifica nenhum estado.
Solução de problemas
Registo
Para habilitar o registo de depuração ou rastreamento para a autenticação de Blazor WebAssembly, consulte o registo de ASP.NET Core Blazor.
Erros comuns
Verifique a configuração de cada projeto. Confirme se os URLs estão corretos:
- projeto
Backend
appsettings.json
BackendUrl
FrontendUrl
-
Backend.http
:Backend_HostAddress
-
BlazorWasmAuth
projeto:wwwroot/appsettings.json
BackendUrl
FrontendUrl
Se a configuração parecer correta:
Analise os logs do aplicativo.
Examine o tráfego de rede entre o aplicativo
BlazorWasmAuth
eBackend
aplicativo com as ferramentas de desenvolvedor do navegador. Muitas vezes, uma mensagem de erro exata ou uma mensagem com uma pista do que está causando o problema é retornada ao cliente pelo aplicativo de back-end depois de fazer uma solicitação. A orientação das ferramentas de desenvolvedor pode ser encontrada nos seguintes artigos:Google Chrome (documentação do Google)
Mozilla Firefox (documentação da Mozilla)
A equipe de documentação responde a comentários de documentos e bugs em artigos. Abra um problema usando o link Abrir um problema de documentação na parte inferior do artigo. A equipe não é capaz de fornecer suporte ao produto. Vários fóruns públicos de suporte estão disponíveis para ajudar na solução de problemas de um aplicativo. Recomendamos o seguinte:
Os fóruns anteriores não pertencem nem são controlados pela Microsoft.
Para relatórios de bugs de estrutura reproduzíveis que não estejam relacionados à segurança, não sejam sensíveis nem confidenciais, abra um problema com a unidade de produto ASP.NET Core. Não abra um problema com a unidade de produto até que você tenha investigado completamente a causa de um problema e não possa resolvê-lo sozinho e com a ajuda da comunidade em um fórum de suporte público. A unidade de produto não é capaz de solucionar problemas de aplicativos individuais que estão quebrados devido a simples erros de configuração ou casos de uso envolvendo serviços de terceiros. Se um relatório for de natureza sensível ou confidencial ou descrever uma possível falha de segurança no produto que os ciberatacantes podem explorar, consulte Relatando problemas de segurança e bugs (dotnet/aspnetcore
repositório GitHub).
Cookies e dados do site
Os cookies e os dados do site podem persistir nas atualizações do aplicativo e interferir nos testes e na solução de problemas. Limpe o seguinte ao fazer alterações no código do aplicativo, alterações na conta do usuário ou alterações na configuração do aplicativo:
- Cookies de sessão de utilizador
- Cookies de aplicações
- Dados do site em cache e armazenados
Uma abordagem para evitar que cookies persistentes e dados do site interfiram com testes e solução de problemas é:
- Configurar um navegador
- Use um navegador para testar que você pode configurar para excluir todos os dados cookie e do site sempre que o navegador for fechado.
- Verifique se o navegador está fechado manualmente ou pelo IDE para qualquer alteração na configuração do aplicativo, do usuário de teste ou do provedor.
- Use um comando personalizado para abrir um navegador no modo InPrivate ou de navegação anônima no Visual Studio:
- Abra caixa de diálogo Procurar com no botão Executar do Visual Studio.
- Selecione o botão Adicionar.
- Forneça o caminho para o seu navegador no campo Programa. Os seguintes caminhos executáveis são locais de instalação típicos para o Windows 10. Se o seu navegador estiver instalado em um local diferente ou você não estiver usando o Windows 10, forneça o caminho para o executável do navegador.
- Microsoft Edge:
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
- Google Chrome:
C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
- Mozilla Firefox:
C:\Program Files\Mozilla Firefox\firefox.exe
- Microsoft Edge:
- No campo Argumentos, forneça a opção de linha de comando que o navegador usa para abrir no modo InPrivate ou Incógnito. Alguns navegadores exigem o URL do aplicativo.
- Microsoft Edge: Use
-inprivate
. - Google Chrome: use o
--incognito --new-window {URL}
, onde o espaço reservado{URL}
é o URL a ser aberto (por exemplo,https://localhost:5001
). - Mozilla Firefox: Use
-private -url {URL}
, onde o marcador de posição{URL}
é o URL a ser aberto (por exemplo,https://localhost:5001
).
- Microsoft Edge: Use
- Forneça um nome no campo Nome fácil de lembrar. Por exemplo,
Firefox Auth Testing
. - Selecione o botão OK.
- Para evitar ter que selecionar o perfil do navegador para cada iteração de teste com um aplicativo, defina o perfil como padrão com o botão Definir como Padrão.
- Certifique-se de que o navegador está fechado pelo IDE para qualquer alteração na configuração do aplicativo, usuário de teste ou provedor.
Atualizações de aplicativos
Um aplicativo em funcionamento pode falhar imediatamente após atualizar o SDK do .NET Core na máquina de desenvolvimento ou alterar as versões do pacote no aplicativo. Em alguns casos, pacotes incoerentes podem quebrar um aplicativo ao executar grandes atualizações. A maioria desses problemas pode ser corrigida seguindo estas instruções:
- Limpe os caches de pacotes NuGet do sistema local executando
dotnet nuget locals all --clear
a partir de um shell de comando. - Exclua as pastas
bin
eobj
do projeto. - Restaure e reconstrua o projeto.
- Exclua todos os arquivos na pasta de implantação no servidor antes de reimplantar o aplicativo.
Observação
Não há suporte para o uso de versões de pacote incompatíveis com a estrutura de destino do aplicativo. Para obter informações sobre um pacote, use o Galeria NuGet ou Explorador de Pacotes FuGet.
Inspecionar as reclamações do usuário
Para solucionar problemas com declarações de usuário, o componente UserClaims
a seguir pode ser usado diretamente em aplicativos ou servir como base para personalização adicional.
UserClaims.razor
:
@page "/user-claims"
@using System.Security.Claims
@attribute [Authorize]
<PageTitle>User Claims</PageTitle>
<h1>User Claims</h1>
**Name**: @AuthenticatedUser?.Identity?.Name
<h2>Claims</h2>
@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
<p class="claim">@(claim.Type): @claim.Value</p>
}
@code {
[CascadingParameter]
private Task<AuthenticationState>? AuthenticationState { get; set; }
public ClaimsPrincipal? AuthenticatedUser { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthenticationState is not null)
{
var state = await AuthenticationState;
AuthenticatedUser = state.User;
}
}
}