Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описывается, как обеспечить безопасность Blazor Web App с помощью проверки подлинности Windows с использованием образца приложения. Дополнительные сведения см. в статье Настройка проверки подлинности Windows в ASP.NET Core.
Спецификация приложения для Blazor Web App:
- Использует интерактивный режим сервера с глобальной интерактивностью.
- Устанавливает политику авторизации для идентификатора безопасности Windows для доступа к безопасной странице.
Пример приложения
Доступ к образцу можно получить через папку с последней версией в репозитории образцов Blazor, используя следующую ссылку. Пример находится в папке BlazorWebAppWinAuthServer для .NET 9 или более поздней версии.
Просмотреть или скачать образец кода (описание загрузки)
Конфигурация
Пример приложения не требует конфигурации для локального запуска.
При развертывании на хосте, таком как IIS, приложению необходимо использовать режим олицетворения, чтобы выполняться под учетной записью пользователя. Дополнительные сведения см. в статье Настройка проверки подлинности Windows в ASP.NET Core.
Пример кода приложения
Program Проверьте файл в примере приложения для следующих вызовов API.
AddAuthentication вызывается с помощью NegotiateDefaults.AuthenticationScheme схемы проверки подлинности. AddNegotiate настраивает AuthenticationBuilder для использования аутентификации Negotiate (также известной как Windows, Kerberos или NTLM), а обработчик аутентификации поддерживает Kerberos на серверах Windows и Linux.
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
AddAuthorization добавляет службы политики авторизации. AuthorizationOptions.FallbackPolicy задает резервную политику авторизации, которая задана для политики по умолчанию (AuthorizationOptions.DefaultPolicy). Политика по умолчанию требует от пользователя, прошедшего проверку подлинности, для доступа к приложению:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
AddCascadingAuthenticationState добавляет каскадное состояние аутентификации в коллекцию сервисов. Это эквивалентно размещению CascadingAuthenticationState компонента в корне иерархии компонентов приложения:
builder.Services.AddCascadingAuthenticationState();
Политика авторизации добавляется для идентификатора безопасности Windows (SID). Известный S-1-5-113 SID в следующем примере указывает, что пользователь является локальной учетной записью. Это ограничивает сетевой вход только на локальные учетные записи, а не на "администратора" или эквивалентные учетные записи.
builder.Services.AddAuthorizationBuilder()
.AddPolicy("LocalAccount", policy =>
policy.RequireClaim(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
"S-1-5-113"));
Политика авторизации применяется компонентом LocalAccount .
Components/Pages/LocalAccount.razor:
@page "/local-account"
@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>
Компонент UserClaims перечисляет утверждения и роли пользователя, включая идентификаторы безопасности Windows (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";
}
}
}
Дополнительные ресурсы
ASP.NET Core