Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo descreve como proteger um Blazor Web App com a Autenticação do Windows usando um aplicativo de exemplo. Para obter mais informações, consulte Configurar a Autenticação do Windows no ASP.NET Core.
A especificação do aplicativo para o Blazor Web App:
- Adota o modo de renderização do Servidor Interativo com interatividade global.
- Estabelece uma política de autorização para um identificador de segurança do Windows acessar uma página segura.
Aplicativo de exemplo
Acesse o exemplo por meio da pasta de versão mais recente no Blazor repositório de exemplos com o link a seguir. O exemplo está na BlazorWebAppWinAuthServer pasta para .NET 9 ou posterior.
Exibir ou baixar código de exemplo (como baixar)
Configuração
O aplicativo de exemplo não requer configuração para ser executado localmente.
Quando implantado em um host, como o IIS, o aplicativo deve adotar a impersonação para ser executado na conta do usuário. Para obter mais informações, consulte Configurar a Autenticação do Windows no ASP.NET Core.
Código de aplicativo de exemplo
Inspecione o Program arquivo no aplicativo de exemplo para as chamadas à API a seguir.
AddAuthentication é chamado usando o esquema de autenticação NegotiateDefaults.AuthenticationScheme. AddNegotiate configura o AuthenticationBuilder para usar a autenticação Negociar (também conhecida como Windows, Kerberos ou NTLM), e o manipulador de autenticação oferece suporte ao Kerberos em servidores Windows e Linux:
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
AddAuthorization adiciona serviços de política de autorização. AuthorizationOptions.FallbackPolicy define a política de autorização de fallback, que é definida como a política padrão (AuthorizationOptions.DefaultPolicy). A política padrão requer que um usuário autenticado acesse o aplicativo:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
AddCascadingAuthenticationState adiciona o estado de autenticação em cascata à coleção de serviços. Isso é equivalente a colocar um CascadingAuthenticationState componente na raiz da hierarquia de componentes do aplicativo:
builder.Services.AddCascadingAuthenticationState();
Uma política de autorização é adicionada para um SID (identificador de segurança) do Windows. O S-1-5-113 SID conhecido no exemplo a seguir indica que o usuário é uma conta local, que restringe a entrada de rede a contas locais em vez de "administrador" ou contas equivalentes:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("LocalAccount", policy =>
policy.RequireClaim(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
"S-1-5-113"));
A política de autorização é imposta pelo LocalAccountOnly componente.
Components/Pages/LocalAccountOnly.razor:
@page "/local-account-only"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize("LocalAccount")]
<h1>Local Account Only</h1>
<p>
You can only reach this page by satisfying the
<code>LocalAccount</code> authorization policy.
</p>
O UserClaims componente lista as declarações e roles do usuário, incluindo os SIDs (identificadores de segurança do Windows) do usuário com traduções de SID.
Components/Pages/UserClaims.razor:
@page "/user-claims"
@using System.Security.Claims
@using System.Security.Principal
@using Microsoft.AspNetCore.Components.QuickGrid
<PageTitle>User Claims & Roles</PageTitle>
<h1>User Claims & Roles</h1>
<QuickGrid Items="claims" Pagination="pagination">
<Paginator State="pagination" />
<PropertyColumn Property="@(p => p.Type)" Sortable="true" />
<PropertyColumn Property="@(p => p.Value)" Sortable="true" />
<PropertyColumn Property="@(p => GetClaimAsHumanReadable(p))" Sortable="true" Title="Translation" />
<PropertyColumn Property="@(p => p.Issuer)" Sortable="true" />
</QuickGrid>
<h1>User Roles</h1>
@if (roles.Any())
{
<ul>
@foreach (var role in roles)
{
<li>@role</li>
}
</ul>
}
else
{
<p>No roles available.</p>
}
@code {
private IQueryable<Claim> claims = Enumerable.Empty<Claim>().AsQueryable();
private IEnumerable<string> roles = Enumerable.Empty<string>();
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthState == null)
{
return;
}
var authState = await AuthState;
claims = authState.User.Claims.AsQueryable();
roles = authState.User.Claims
.Where(claim => claim.Type == ClaimTypes.Role)
.Select(claim => claim.Value);
}
private string GetClaimAsHumanReadable(Claim claim)
{
if (!OperatingSystem.IsWindows() ||
claim.Type is not (ClaimTypes.PrimarySid or ClaimTypes.PrimaryGroupSid
or ClaimTypes.GroupSid))
{
// We're either not on Windows or not dealing with a SID Claim that
// can be translated
return string.Empty;
}
SecurityIdentifier sid = new SecurityIdentifier(claim.Value);
try
{
// Throw an exception if the SID can't be translated
var account = sid.Translate(typeof(NTAccount));
return account.ToString();
}
catch (IdentityNotMappedException)
{
return "Could not be mapped";
}
}
}