Проверка подлинности и авторизация в ASP.NET Core Blazor

В этой статье приводятся сведения о поддержке настройки и администрирования функций безопасности в ASP.NET Core для приложений Blazor.

Сценарии безопасности для приложений Blazor Server и Blazor WebAssembly отличаются. Так как приложения Blazor Server выполняются на стороне сервера, проверки авторизации могут определить следующее:

  • параметры пользовательского интерфейса, предоставленные пользователю (например, какие пункты меню доступны пользователю);
  • правила доступа для приложений и компонентов.

Приложения Blazor WebAssembly выполняются на стороне клиента. В этом случае авторизация используется только для определения отображаемых вариантов пользовательского интерфейса. Так как пользователь может изменить или обойти проверки на стороне клиента, приложение Blazor WebAssembly не может применять правила авторизации доступа.

Соглашения об авторизации Razor Pages не применяются к маршрутизируемым компонентам Razor. Если компонент Razor, не поддерживающий маршрутизацию, встроен в страницу, соглашения об авторизации страницы оказывают косвенное влияние на компонент Razor, а также на остальную часть содержимого страницы.

Identity ASP.NET Core предназначена для работы в контексте обмена http-запросами и ответами, которые обычно не являются моделью взаимодействия между клиентом и сервером Blazor приложения. В приложениях ASP.NET Core, применяющих ASP.NET Core Identity для управления пользователями, следует использовать Razor Pages вместо компонентов Razor для пользовательского интерфейса, связанного с Identity, например для регистрации пользователей, входа, выхода и других задач управления пользователями.

Абстракции ASP.NET Core, например SignInManager<TUser> и UserManager<TUser>, не поддерживаются в компонентах Razor. Дополнительные сведения об использовании ASP.NET Core Identity с Blazor см. в Добавление шаблона ASP.NET Core Identity в приложение Blazor Server.

Проверка подлинности

Blazor использует существующие механизмы проверки подлинности ASP.NET Core для установления личности пользователя. Конкретный механизм зависит от того, как размещается приложение Blazor (Blazor WebAssembly или Blazor Server).

Blazor WebAssembly аутентификация

В приложениях Blazor WebAssembly проверку подлинности можно обойти, так как пользователь может изменять весь код на стороне клиента. Это же справедливо для всех технологий на стороне клиента, включая платформы одностраничного приложения JavaScript или собственных приложений для любой операционной системы.

Добавьте следующий код:

Вопросы обработки проверки подлинности и использования встроенной или настраиваемой службы AuthenticationStateProvider рассматриваются в следующих разделах.

Дополнительные сведения о создании приложений и конфигураций см. в статье Защита ASP.NET Core Blazor WebAssembly.

Blazor Server аутентификация

Приложения Blazor Server работают через подключение в реальном времени, созданное с помощью SignalR. Проверка подлинности в приложениях на основе SignalR выполняется при установлении подключения. Аутентификация может выполняться на основе cookie или других маркеров носителя.

Встроенная служба AuthenticationStateProvider для приложений Blazor Server получает данные о состоянии проверки подлинности из HttpContext.User в ASP.NET Core. Так состояние проверки подлинности интегрируется с существующими соответствующими механизмами проверки подлинности ASP.NET Core.

Важно!

Не используйте IHttpContextAccessor в Razor компонентах приложений Blazor Server . Приложения Blazor запускаются вне контекста конвейера ASP.NET Core. Не HttpContext гарантируется, что он будет доступен в IHttpContextAccessorи HttpContext не будет содержать контекст, запускающий Blazor приложение. Дополнительные сведения см. в разделе Последствия для безопасности при использовании IHttpContextAccessor в Blazor Server (dotnet/aspnetcore #45699). Дополнительные сведения о поддержании пользовательского состояния в приложениях см. в Blazor Server разделе управление состоянием ASP.NET CoreBlazor.

Дополнительные сведения о создании и настройке приложений см. в статье Защита приложений ASP.NET Core Blazor Server.

Служба AuthenticationStateProvider

AuthenticationStateProvider является базовой службой, которую компоненты AuthorizeView и CascadingAuthenticationState используют для получения состояния аутентификации.

Обычно вы не используете AuthenticationStateProvider напрямую. Выберите подход с использованием компонента AuthorizeView или Task<AuthenticationState>, как описано далее в этой статье. Основной недостаток при использовании AuthenticationStateProvider напрямую заключается в том, что компонент не получает автоматического уведомления при изменении базовых данных о состоянии аутентификации.

Служба AuthenticationStateProvider может предоставить данные ClaimsPrincipal о текущем пользователе, как показано в следующем примере:

@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>ClaimsPrincipal Data</h3>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Count() > 0)
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surnameMessage</p>

@code {
    private string authMessage;
    private string surnameMessage;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surnameMessage = 
                $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, а пользователь является ClaimsPrincipal, можно перечислить утверждения и оценить членство в ролях.

Дополнительные сведения о внедрении зависимостей и службах см. в статье Внедрение зависимостей ASP.NET Core Blazor и Внедрение зависимостей в ASP.NET Core. Сведения о реализации пользовательского поставщика AuthenticationStateProvider в приложениях Blazor Server см. в статье Защита приложений ASP.NET Core Blazor Server.

Предоставление состояния аутентификации в качестве каскадного параметра

Если процедурная логика требует данных о состоянии аутентификации, например при выполнении активируемых пользователем действий, для получения таких данных определите каскадный параметр типа Task<AuthenticationState>:

@page "/"

<button @onclick="LogUsername">Log username</button>

<p>@authMessage</p>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, можно перечислить утверждения и оценить членство в ролях.

Настройте каскадный параметр Task<AuthenticationState> с помощью компонентов AuthorizeRouteView и CascadingAuthenticationState в компоненте App (App.razor).

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

В приложении Blazor WebAssembly добавьте службы для параметров и авторизации в Program.cs:

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

В приложении Blazor Server уже есть службы для параметров и авторизации, поэтому ничего делать не нужно.

Авторизация

После аутентификации пользователя применяются правила авторизации, которые определяют доступные этому пользователю действия.

Доступ обычно предоставляется или запрещается в зависимости от следующих аспектов:

  • выполнена ли аутентификация (выполнен ли вход);
  • есть ли у пользователя определенная роль;
  • есть ли у пользователя определенное утверждение;
  • выполняются ли требования политики.

Каждый из этих аспектов применяется здесь так же, как в приложениях ASP.NET Core MVC или Razor Pages. Дополнительные сведения о безопасности в ASP.NET Core вы найдете в статьях о безопасности и Identity в ASP.NET Core.

Компонент AuthorizeView

Компонент AuthorizeView избирательно демонстрирует содержимое пользовательского интерфейса в зависимости от того, авторизован ли пользователь. Этот подход полезен, если вам нужно просто отображать пользователю данные, и не использовать удостоверение пользователя в процедурной логике.

Этот компонент представляет переменную context типа AuthenticationState, которую можно использовать для доступа к сведениям о пользователе, выполнившем вход:

<AuthorizeView>
    <h1>Hello, @context.User.Identity.Name!</h1>
    <p>You can only see this content if you're authenticated.</p>
</AuthorizeView>

Также вы можете указать другое содержимое, которое будет отображаться, если пользователь не авторизован:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authorized.</p>
        <button @onclick="SecureMethod">Authorized Only Button</button>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void SecureMethod() { ... }
}

Содержимое тегов <Authorized> и <NotAuthorized> может включать произвольные элементы, например другие интерактивные компоненты.

Обработчик событий по умолчанию для авторизованного элемента, например, метод SecureMethod для элемента <button> в предыдущем примере, может вызываться только авторизованным пользователем.

Условия авторизации, такие как роли или правила для выбора вариантов пользовательского интерфейса и доступа к ним, описаны в разделе об авторизации.

Если условия авторизации не указаны, AuthorizeView использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Компонент AuthorizeView можно использовать в компоненте NavMenu (Shared/NavMenu.razor) для отображения компонента NavLink (NavLink), но следует учитывать, что при использовании этого подхода удаляется только элемент списка из отображаемых выходных данных. Пользователь по-прежнему может переходить к компоненту.

Приложения, созданные на основе шаблона проекта Blazor, который включает проверку подлинности, используют компонент LoginDisplay, который зависит от компонента AuthorizeView. Компонент AuthorizeView выборочно отображает пользователям содержимое для операций, связанных с Identity. Следующий пример относится к шаблону проекта Blazor WebAssembly.

Shared/LoginDisplay.razor:

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity?.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogOut">Log out</button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code{
    public void BeginLogOut()
    {
        Navigation.NavigateToLogout("authentication/logout");
    }
}

Следующий пример относится к шаблону проекта Blazor Server и использует конечные точки ASP.NET Core Identity в области Identity приложения для обработки операций, связанных с Identity.

Shared/LoginDisplay.razor:

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Авторизация на основе ролей и политик

Компонент AuthorizeView поддерживает авторизацию на основе ролей или политик.

Для авторизации на основе ролей используйте Roles параметр . В следующем примере пользователь должен иметь утверждение роли для (или обеих) Admin ролей или Superuser :

<AuthorizeView Roles="Admin, Superuser">
    <p>You can only see this if you're an Admin or Superuser.</p>
</AuthorizeView>

Дополнительные сведения, включая инструкции по настройке, см. в статье Авторизация на основе ролей в ASP.NET Core.

Для авторизации на основе политик примените параметр Policy:

<AuthorizeView Policy="ContentEditor">
    <p>You can only see this if you satisfy the "ContentEditor" policy.</p>
</AuthorizeView>

Авторизация на основе утверждений считается особым случаем авторизации на основе политик. Например, вы можете определить политику, которая требует наличия определенного утверждения у пользователя. Дополнительные сведения см. в статье Авторизация на основе политик в ASP.NET Core.

Эти API-интерфейсы можно использовать в приложениях Blazor Server или Blazor WebAssembly.

Если не указано ни Roles, ни Policy, AuthorizeView использует политику по умолчанию.

Так как сравнение строк .NET по умолчанию учитывает регистр, соответствующие имена ролей и политик также чувствительны к регистру. Например, Admin (в верхнем регистре A) не рассматривается как роль admin (в нижнем регистре a).

Регистр Pascal обычно используется для имен ролей и политик (например, BillingAdministrator), но использование регистра Pascal не является строгим требованием. Разрешены различные схемы насадки, такие как верблюда, кебаб и змеиный случай. Использование пробелов в именах ролей и политик также является необычным, но разрешенным. Например, billing administrator это необычный формат имени роли или политики в приложениях .NET, но допустимый.

Содержимое, отображаемое при асинхронной аутентификации

Blazor позволяет асинхронно определять состояние проверки подлинности. Основной сценарий для такого подхода — приложение Blazor WebAssembly, которое направляет запрос на проверку подлинности во внешнюю конечную точку.

Пока аутентификация выполняется, AuthorizeView по умолчанию не отображает содержимое. Для отображения содержимого в ходе проверки подлинности используйте тег <Authorizing>:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authenticated.</p>
    </Authorized>
    <Authorizing>
        <h1>Authentication in progress</h1>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

Такой подход обычно не применим к приложениям Blazor Server. Приложения Blazor Server узнают состояние проверки подлинности, как только оно устанавливается. Содержимое Authorizing можно указать в компоненте AuthorizeView для приложения Blazor Server, но это содержимое никогда не отображается.

Атрибут [Authorize]

Атрибут [Authorize] можно использовать в компонентах Razor:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Важно!

Используйте [Authorize] только для компонентов @page, полученных через маршрутизатор Blazor. Авторизация выполняется только как аспект маршрутизации и не для дочерних компонентов, которые отображаются на странице. Чтобы разрешить отображение конкретных частей на странице, используйте вместо этого AuthorizeView.

Атрибут [Authorize] также поддерживает авторизацию на основе ролей или политик. Для авторизации на основе ролей примените параметр Roles:

@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

Для авторизации на основе политик примените параметр Policy:

@page "/"
@attribute [Authorize(Policy = "ContentEditor")]

<p>You can only see this if you satisfy the 'ContentEditor' policy.</p>

Если не указано ни Roles, ни Policy, [Authorize] использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Авторизация ресурсов

Чтобы авторизовать пользователей для доступа к ресурсам, передайте данные маршрута запроса в параметр Resource в AuthorizeRouteView.

В содержимом Router.Found для запрошенного маршрута в компоненте App (App.razor):

<AuthorizeRouteView Resource="@routeData" RouteData="@routeData" 
    DefaultLayout="@typeof(MainLayout)" />

Дополнительные сведения о том, как данные состояния авторизации передаются и используются в процедурной логике, см. в статье Предоставление состояния аутентификации в качестве каскадного параметра.

Когда объект AuthorizeRouteView получает данные маршрута для ресурса, политики авторизации получают доступ к RouteData.PageType и RouteData.RouteValues, в результате чего разрешается использовать настраиваемую логику для принятия решений об авторизации.

В следующем примере в AuthorizationOptions создается политика EditUser для конфигурации службы авторизации приложения (AddAuthorizationCore) с помощью следующей логики:

  • Определение того, существует ли значение маршрута с ключом id. Если ключ существует, значение маршрута сохраняется в value.
  • В переменной с именем id сохраните value в виде строки или задайте пустое строковое значение (string.Empty).
  • Если id не является пустой строкой, следует подтвердить, что условия политики соблюдены (возвращается true), если значение строки начинается с EMP. В противном случае следует подтвердить, что политика завершается ошибкой (возвращается false).

В Program.cs или Startup.cs (в зависимости от модели размещения и версии платформы):

  • Добавьте пространства имен для Microsoft.AspNetCore.Components и System.Linq:

    using Microsoft.AspNetCore.Components;
    using System.Linq;
    
  • Добавьте политику:

    options.AddPolicy("EditUser", policy =>
        policy.RequireAssertion(context =>
        {
            if (context.Resource is RouteData rd)
            {
                var routeValue = rd.RouteValues.TryGetValue("id", out var value);
                var id = Convert.ToString(value, 
                    System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty;
    
                if (!string.IsNullOrEmpty(id))
                {
                    return id.StartsWith("EMP", StringComparison.InvariantCulture);
                }
            }
    
            return false;
        })
    );
    

Предыдущий пример — это упрощенная политика авторизации, используемая исключительно для демонстрации концепции с рабочим примером. Дополнительные сведения о создании и настройке политик авторизации см. в статье Авторизация на основе политик в ASP.NET Core.

В следующем компоненте EditUser ресурс в /users/{id}/edit имеет параметр маршрута для идентификатора пользователя ({id}). Компонент использует предыдущую политику авторизации EditUser, чтобы определить, будет ли значение маршрута id начинаться с EMP. Если id начинается с EMP, политика будет успешно применена, и доступ к компоненту будет разрешен. Если id начинается со значения, отличного от EMP, или если id является пустой строкой, то политика завершается ошибкой и компонент не загружается.

Pages/EditUser.razor:

@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]

<h1>Edit User</h1>

<p>The 'EditUser' policy is satisfied! <code>Id</code> starts with 'EMP'.</p>

@code {
    [Parameter]
    public string Id { get; set; }
}

Настройка несанкционированного содержимого для компонента маршрутизатора

Компонент Router вместе с компонентом AuthorizeRouteView позволяет приложению указать пользовательское содержимое для следующих ситуаций:

  • пользователь не удовлетворяет условию [Authorize], которое применено к компоненту Отображается разметка для элемента <NotAuthorized>. (атрибут [Authorize] описан в разделе Атрибут [Authorize]);
  • Выполняется асинхронная авторизация. Как правило, это означает, что выполняется проверка подлинности пользователя. Отображается разметка для элемента <Authorizing>.
  • Содержимое не найдено. Отображается разметка для элемента <NotFound>.

В компоненте App (App.razor):

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView ...>
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Содержимое тегов <NotFound>, <NotAuthorized> и <Authorizing> может включать произвольные элементы, например другие интерактивные компоненты.

Если тег <NotAuthorized> не указан, то AuthorizeRouteView использует следующее резервное сообщение:

Not authorized.

Процедурная логика

Если приложению нужно проверять правила авторизации в составе процедурной логики, используйте каскадный параметр с типом Task<AuthenticationState>, чтобы получить ClaimsPrincipal пользователя. Task<AuthenticationState> можно комбинировать для оценки политик с другими службами, например IAuthorizationService.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the 
            // 'content-editor' policy.
        }
    }
}

Примечание

В компоненте приложения Blazor WebAssembly добавьте пространства имен Microsoft.AspNetCore.Authorization и Microsoft.AspNetCore.Components.Authorization:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

Эти пространства имен можно предоставить глобально, добавив их в файл _Imports.razor приложения.

Устранение неполадок

Распространенные ошибки

  • Для авторизации требуется каскадный параметр с типом Task<AuthenticationState>. Чтобы предоставить его, попробуйте использовать CascadingAuthenticationState.

  • Для authenticationStateTask возвращается значение null

Вполне вероятно, что проект не был создан на основе шаблона приложения Blazor Server с включенной проверкой подлинности. Примените <CascadingAuthenticationState> в качестве оболочки определенной части дерева пользовательского интерфейса, например в компоненте App (App.razor), следующим образом.

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

CascadingAuthenticationState предоставляет каскадный параметр Task<AuthenticationState>, который он, в свою очередь, получает из базовой службы внедрения зависимостей AuthenticationStateProvider.

Дополнительные ресурсы

Сценарии безопасности для приложений Blazor Server и Blazor WebAssembly отличаются. Так как приложения Blazor Server выполняются на стороне сервера, проверки авторизации могут определить следующее:

  • параметры пользовательского интерфейса, предоставленные пользователю (например, какие пункты меню доступны пользователю);
  • правила доступа для приложений и компонентов.

Приложения Blazor WebAssembly выполняются на стороне клиента. В этом случае авторизация используется только для определения отображаемых вариантов пользовательского интерфейса. Так как пользователь может изменить или обойти проверки на стороне клиента, приложение Blazor WebAssembly не может применять правила авторизации доступа.

Соглашения об авторизации Razor Pages не применяются к маршрутизируемым компонентам Razor. Если компонент Razor, не поддерживающий маршрутизацию, встроен в страницу, соглашения об авторизации страницы оказывают косвенное влияние на компонент Razor, а также на остальную часть содержимого страницы.

Identity ASP.NET Core предназначена для работы в контексте обмена данными http-запросов и ответов, которые обычно не являются моделью взаимодействия между клиентом и сервером Blazor приложения. В приложениях ASP.NET Core, применяющих ASP.NET Core Identity для управления пользователями, следует использовать Razor Pages вместо компонентов Razor для пользовательского интерфейса, связанного с Identity, например для регистрации пользователей, входа, выхода и других задач управления пользователями.

Абстракции ASP.NET Core, например SignInManager<TUser> и UserManager<TUser>, не поддерживаются в компонентах Razor. Дополнительные сведения об использовании ASP.NET Core Identity с Blazor см. в Добавление шаблона ASP.NET Core Identity в приложение Blazor Server.

Проверка подлинности

Blazor использует существующие механизмы проверки подлинности ASP.NET Core для установления личности пользователя. Конкретный механизм зависит от того, как размещается приложение Blazor (Blazor WebAssembly или Blazor Server).

Blazor WebAssembly аутентификация

В приложениях Blazor WebAssembly проверку подлинности можно обойти, так как пользователь может изменять весь код на стороне клиента. Это же справедливо для всех технологий на стороне клиента, включая платформы одностраничного приложения JavaScript или собственных приложений для любой операционной системы.

Добавьте следующий код:

Вопросы обработки проверки подлинности и использования встроенной или настраиваемой службы AuthenticationStateProvider рассматриваются в следующих разделах.

Дополнительные сведения о создании приложений и конфигураций см. в статье Защита ASP.NET Core Blazor WebAssembly.

Blazor Server аутентификация

Приложения Blazor Server работают через подключение в реальном времени, созданное с помощью SignalR. Проверка подлинности в приложениях на основе SignalR выполняется при установлении подключения. Аутентификация может выполняться на основе cookie или других маркеров носителя.

Встроенная служба AuthenticationStateProvider для приложений Blazor Server получает данные о состоянии проверки подлинности из HttpContext.User в ASP.NET Core. Так состояние проверки подлинности интегрируется с существующими соответствующими механизмами проверки подлинности ASP.NET Core.

Важно!

Не используйте IHttpContextAccessor в Razor компонентах приложений Blazor Server . Приложения Blazor запускаются вне контекста конвейера ASP.NET Core. Не HttpContext гарантируется, что он будет доступен в IHttpContextAccessorи HttpContext не будет содержать контекст, запускающий Blazor приложение. Дополнительные сведения см. в разделе Последствия для безопасности при использовании IHttpContextAccessor в Blazor Server (dotnet/aspnetcore #45699). Дополнительные сведения о поддержании пользовательского состояния в приложениях см. в Blazor Server разделе управление состоянием ASP.NET CoreBlazor.

Дополнительные сведения о создании и настройке приложений см. в статье Защита приложений ASP.NET Core Blazor Server.

Служба AuthenticationStateProvider

AuthenticationStateProvider является базовой службой, которую компоненты AuthorizeView и CascadingAuthenticationState используют для получения состояния аутентификации.

Обычно вы не используете AuthenticationStateProvider напрямую. Выберите подход с использованием компонента AuthorizeView или Task<AuthenticationState>, как описано далее в этой статье. Основной недостаток при использовании AuthenticationStateProvider напрямую заключается в том, что компонент не получает автоматического уведомления при изменении базовых данных о состоянии аутентификации.

Служба AuthenticationStateProvider может предоставить данные ClaimsPrincipal о текущем пользователе, как показано в следующем примере:

@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>ClaimsPrincipal Data</h3>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Count() > 0)
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surnameMessage</p>

@code {
    private string authMessage;
    private string surnameMessage;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surnameMessage = 
                $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, а пользователь является ClaimsPrincipal, можно перечислить утверждения и оценить членство в ролях.

Дополнительные сведения о внедрении зависимостей и службах см. в статье Внедрение зависимостей ASP.NET Core Blazor и Внедрение зависимостей в ASP.NET Core. Сведения о реализации пользовательского поставщика AuthenticationStateProvider в приложениях Blazor Server см. в статье Защита приложений ASP.NET Core Blazor Server.

Предоставление состояния аутентификации в качестве каскадного параметра

Если процедурная логика требует данных о состоянии аутентификации, например при выполнении активируемых пользователем действий, для получения таких данных определите каскадный параметр типа Task<AuthenticationState>:

@page "/"

<button @onclick="LogUsername">Log username</button>

<p>@authMessage</p>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, можно перечислить утверждения и оценить членство в ролях.

Настройте каскадный параметр Task<AuthenticationState> с помощью компонентов AuthorizeRouteView и CascadingAuthenticationState в компоненте App (App.razor).

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

В приложении Blazor WebAssembly добавьте службы для параметров и авторизации в Program.cs:

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

В приложении Blazor Server уже есть службы для параметров и авторизации, поэтому ничего делать не нужно.

Авторизация

После аутентификации пользователя применяются правила авторизации, которые определяют доступные этому пользователю действия.

Доступ обычно предоставляется или запрещается в зависимости от следующих аспектов:

  • выполнена ли аутентификация (выполнен ли вход);
  • есть ли у пользователя определенная роль;
  • есть ли у пользователя определенное утверждение;
  • выполняются ли требования политики.

Каждый из этих аспектов применяется здесь так же, как в приложениях ASP.NET Core MVC или Razor Pages. Дополнительные сведения о безопасности в ASP.NET Core вы найдете в статьях о безопасности и Identity в ASP.NET Core.

Компонент AuthorizeView

Компонент AuthorizeView избирательно демонстрирует содержимое пользовательского интерфейса в зависимости от того, авторизован ли пользователь. Этот подход полезен, если вам нужно просто отображать пользователю данные, и не использовать удостоверение пользователя в процедурной логике.

Этот компонент представляет переменную context типа AuthenticationState, которую можно использовать для доступа к сведениям о пользователе, выполнившем вход:

<AuthorizeView>
    <h1>Hello, @context.User.Identity.Name!</h1>
    <p>You can only see this content if you're authenticated.</p>
</AuthorizeView>

Также вы можете указать другое содержимое, которое будет отображаться, если пользователь не авторизован:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authorized.</p>
        <button @onclick="SecureMethod">Authorized Only Button</button>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void SecureMethod() { ... }
}

Содержимое тегов <Authorized> и <NotAuthorized> может включать произвольные элементы, например другие интерактивные компоненты.

Обработчик событий по умолчанию для авторизованного элемента, например, метод SecureMethod для элемента <button> в предыдущем примере, может вызываться только авторизованным пользователем.

Условия авторизации, такие как роли или правила для выбора вариантов пользовательского интерфейса и доступа к ним, описаны в разделе об авторизации.

Если условия авторизации не указаны, AuthorizeView использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Компонент AuthorizeView можно использовать в компоненте NavMenu (Shared/NavMenu.razor) для отображения компонента NavLink (NavLink), но следует учитывать, что при использовании этого подхода удаляется только элемент списка из отображаемых выходных данных. Пользователь по-прежнему может переходить к компоненту.

Приложения, созданные на основе шаблона проекта Blazor, который включает проверку подлинности, используют компонент LoginDisplay, который зависит от компонента AuthorizeView. Компонент AuthorizeView выборочно отображает пользователям содержимое для операций, связанных с Identity. Следующий пример относится к шаблону проекта Blazor WebAssembly.

Shared/LoginDisplay.razor:

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code{
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Следующий пример относится к шаблону проекта Blazor Server и использует конечные точки ASP.NET Core Identity в области Identity приложения для обработки операций, связанных с Identity.

Shared/LoginDisplay.razor:

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Авторизация на основе ролей и политик

Компонент AuthorizeView поддерживает авторизацию на основе ролей или политик.

Для авторизации на основе ролей используйте Roles параметр . В следующем примере пользователь должен иметь утверждение роли для (или обеих) Admin ролей или Superuser :

<AuthorizeView Roles="Admin, Superuser">
    <p>You can only see this if you're an Admin or Superuser.</p>
</AuthorizeView>

Дополнительные сведения, включая инструкции по настройке, см. в статье Авторизация на основе ролей в ASP.NET Core.

Для авторизации на основе политик примените параметр Policy:

<AuthorizeView Policy="ContentEditor">
    <p>You can only see this if you satisfy the "ContentEditor" policy.</p>
</AuthorizeView>

Авторизация на основе утверждений считается особым случаем авторизации на основе политик. Например, вы можете определить политику, которая требует наличия определенного утверждения у пользователя. Дополнительные сведения см. в статье Авторизация на основе политик в ASP.NET Core.

Эти API-интерфейсы можно использовать в приложениях Blazor Server или Blazor WebAssembly.

Если не указано ни Roles, ни Policy, AuthorizeView использует политику по умолчанию.

Так как сравнение строк .NET по умолчанию учитывает регистр, соответствующие имена ролей и политик также чувствительны к регистру. Например, Admin (в верхнем регистре A) не рассматривается как роль admin (в нижнем регистре a).

Регистр Pascal обычно используется для имен ролей и политик (например, BillingAdministrator), но использование регистра Pascal не является строгим требованием. Разрешены различные схемы гильз, такие как верблюда, шашлык и змеиный корпус. Использование пробелов в именах ролей и политик также является необычным, но разрешенным. Например, billing administrator это необычный формат имени роли или политики в приложениях .NET, но допустимый.

Содержимое, отображаемое при асинхронной аутентификации

Blazor позволяет асинхронно определять состояние проверки подлинности. Основной сценарий для такого подхода — приложение Blazor WebAssembly, которое направляет запрос на проверку подлинности во внешнюю конечную точку.

Пока аутентификация выполняется, AuthorizeView по умолчанию не отображает содержимое. Для отображения содержимого в ходе проверки подлинности используйте тег <Authorizing>:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authenticated.</p>
    </Authorized>
    <Authorizing>
        <h1>Authentication in progress</h1>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

Такой подход обычно не применим к приложениям Blazor Server. Приложения Blazor Server узнают состояние проверки подлинности, как только оно устанавливается. Содержимое Authorizing можно указать в компоненте AuthorizeView для приложения Blazor Server, но это содержимое никогда не отображается.

Атрибут [Authorize]

Атрибут [Authorize] можно использовать в компонентах Razor:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Важно!

Используйте [Authorize] только для компонентов @page, полученных через маршрутизатор Blazor. Авторизация выполняется только как аспект маршрутизации и не для дочерних компонентов, которые отображаются на странице. Чтобы разрешить отображение конкретных частей на странице, используйте вместо этого AuthorizeView.

Атрибут [Authorize] также поддерживает авторизацию на основе ролей или политик. Для авторизации на основе ролей примените параметр Roles:

@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

Для авторизации на основе политик примените параметр Policy:

@page "/"
@attribute [Authorize(Policy = "ContentEditor")]

<p>You can only see this if you satisfy the 'ContentEditor' policy.</p>

Если не указано ни Roles, ни Policy, [Authorize] использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Авторизация ресурсов

Чтобы авторизовать пользователей для доступа к ресурсам, передайте данные маршрута запроса в параметр Resource в AuthorizeRouteView.

В содержимом Router.Found для запрошенного маршрута в компоненте App (App.razor):

<AuthorizeRouteView Resource="@routeData" RouteData="@routeData" 
    DefaultLayout="@typeof(MainLayout)" />

Дополнительные сведения о том, как данные состояния авторизации передаются и используются в процедурной логике, см. в статье Предоставление состояния аутентификации в качестве каскадного параметра.

Когда объект AuthorizeRouteView получает данные маршрута для ресурса, политики авторизации получают доступ к RouteData.PageType и RouteData.RouteValues, в результате чего разрешается использовать настраиваемую логику для принятия решений об авторизации.

В следующем примере в AuthorizationOptions создается политика EditUser для конфигурации службы авторизации приложения (AddAuthorizationCore) с помощью следующей логики:

  • Определение того, существует ли значение маршрута с ключом id. Если ключ существует, значение маршрута сохраняется в value.
  • В переменной с именем id сохраните value в виде строки или задайте пустое строковое значение (string.Empty).
  • Если id не является пустой строкой, следует подтвердить, что условия политики соблюдены (возвращается true), если значение строки начинается с EMP. В противном случае следует подтвердить, что политика завершается ошибкой (возвращается false).

В Program.cs или Startup.cs (в зависимости от модели размещения и версии платформы):

  • Добавьте пространства имен для Microsoft.AspNetCore.Components и System.Linq:

    using Microsoft.AspNetCore.Components;
    using System.Linq;
    
  • Добавьте политику:

    options.AddPolicy("EditUser", policy =>
        policy.RequireAssertion(context =>
        {
            if (context.Resource is RouteData rd)
            {
                var routeValue = rd.RouteValues.TryGetValue("id", out var value);
                var id = Convert.ToString(value, 
                    System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty;
    
                if (!string.IsNullOrEmpty(id))
                {
                    return id.StartsWith("EMP", StringComparison.InvariantCulture);
                }
            }
    
            return false;
        })
    );
    

Предыдущий пример — это упрощенная политика авторизации, используемая исключительно для демонстрации концепции с рабочим примером. Дополнительные сведения о создании и настройке политик авторизации см. в статье Авторизация на основе политик в ASP.NET Core.

В следующем компоненте EditUser ресурс в /users/{id}/edit имеет параметр маршрута для идентификатора пользователя ({id}). Компонент использует предыдущую политику авторизации EditUser, чтобы определить, будет ли значение маршрута id начинаться с EMP. Если id начинается с EMP, политика будет успешно применена, и доступ к компоненту будет разрешен. Если id начинается со значения, отличного от EMP, или если id является пустой строкой, то политика завершается ошибкой и компонент не загружается.

Pages/EditUser.razor:

@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]

<h1>Edit User</h1>

<p>The 'EditUser' policy is satisfied! <code>Id</code> starts with 'EMP'.</p>

@code {
    [Parameter]
    public string Id { get; set; }
}

Настройка несанкционированного содержимого для компонента маршрутизатора

Компонент Router вместе с компонентом AuthorizeRouteView позволяет приложению указать пользовательское содержимое для следующих ситуаций:

  • пользователь не удовлетворяет условию [Authorize], которое применено к компоненту Отображается разметка для элемента <NotAuthorized>. (атрибут [Authorize] описан в разделе Атрибут [Authorize]);
  • Выполняется асинхронная авторизация. Как правило, это означает, что выполняется проверка подлинности пользователя. Отображается разметка для элемента <Authorizing>.
  • Содержимое не найдено. Отображается разметка для элемента <NotFound>.

В компоненте App (App.razor):

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView ...>
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Содержимое тегов <NotFound>, <NotAuthorized> и <Authorizing> может включать произвольные элементы, например другие интерактивные компоненты.

Если тег <NotAuthorized> не указан, то AuthorizeRouteView использует следующее резервное сообщение:

Not authorized.

Процедурная логика

Если приложению нужно проверять правила авторизации в составе процедурной логики, используйте каскадный параметр с типом Task<AuthenticationState>, чтобы получить ClaimsPrincipal пользователя. Task<AuthenticationState> можно комбинировать для оценки политик с другими службами, например IAuthorizationService.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the 
            // 'content-editor' policy.
        }
    }
}

Примечание

В компоненте приложения Blazor WebAssembly добавьте пространства имен Microsoft.AspNetCore.Authorization и Microsoft.AspNetCore.Components.Authorization:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

Эти пространства имен можно предоставить глобально, добавив их в файл _Imports.razor приложения.

Устранение неполадок

Распространенные ошибки

  • Для авторизации требуется каскадный параметр с типом Task<AuthenticationState>. Чтобы предоставить его, попробуйте использовать CascadingAuthenticationState.

  • Для authenticationStateTask возвращается значение null

Вполне вероятно, что проект не был создан на основе шаблона приложения Blazor Server с включенной проверкой подлинности. Примените <CascadingAuthenticationState> в качестве оболочки определенной части дерева пользовательского интерфейса, например в компоненте App (App.razor), следующим образом.

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

CascadingAuthenticationState предоставляет каскадный параметр Task<AuthenticationState>, который он, в свою очередь, получает из базовой службы внедрения зависимостей AuthenticationStateProvider.

Дополнительные ресурсы

Сценарии безопасности для приложений Blazor Server и Blazor WebAssembly отличаются. Так как приложения Blazor Server выполняются на стороне сервера, проверки авторизации могут определить следующее:

  • параметры пользовательского интерфейса, предоставленные пользователю (например, какие пункты меню доступны пользователю);
  • правила доступа для приложений и компонентов.

Приложения Blazor WebAssembly выполняются на стороне клиента. В этом случае авторизация используется только для определения отображаемых вариантов пользовательского интерфейса. Так как пользователь может изменить или обойти проверки на стороне клиента, приложение Blazor WebAssembly не может применять правила авторизации доступа.

Соглашения об авторизации Razor Pages не применяются к маршрутизируемым компонентам Razor. Если компонент Razor, не поддерживающий маршрутизацию, встроен в страницу, соглашения об авторизации страницы оказывают косвенное влияние на компонент Razor, а также на остальную часть содержимого страницы.

Identity ASP.NET Core предназначена для работы в контексте обмена данными http-запросов и ответов, которые обычно не являются моделью взаимодействия между клиентом и сервером Blazor приложения. В приложениях ASP.NET Core, применяющих ASP.NET Core Identity для управления пользователями, следует использовать Razor Pages вместо компонентов Razor для пользовательского интерфейса, связанного с Identity, например для регистрации пользователей, входа, выхода и других задач управления пользователями.

Абстракции ASP.NET Core, например SignInManager<TUser> и UserManager<TUser>, не поддерживаются в компонентах Razor. Дополнительные сведения об использовании ASP.NET Core Identity с Blazor см. в Добавление шаблона ASP.NET Core Identity в приложение Blazor Server.

Проверка подлинности

Blazor использует существующие механизмы проверки подлинности ASP.NET Core для установления личности пользователя. Конкретный механизм зависит от того, как размещается приложение Blazor (Blazor WebAssembly или Blazor Server).

Blazor WebAssembly аутентификация

В приложениях Blazor WebAssembly проверку подлинности можно обойти, так как пользователь может изменять весь код на стороне клиента. Это же справедливо для всех технологий на стороне клиента, включая платформы одностраничного приложения JavaScript или собственных приложений для любой операционной системы.

Добавьте следующий код:

Вопросы обработки проверки подлинности и использования встроенной или настраиваемой службы AuthenticationStateProvider рассматриваются в следующих разделах.

Дополнительные сведения о создании приложений и конфигураций см. в статье Защита ASP.NET Core Blazor WebAssembly.

Blazor Server аутентификация

Приложения Blazor Server работают через подключение в реальном времени, созданное с помощью SignalR. Проверка подлинности в приложениях на основе SignalR выполняется при установлении подключения. Аутентификация может выполняться на основе cookie или других маркеров носителя.

Встроенная служба AuthenticationStateProvider для приложений Blazor Server получает данные о состоянии проверки подлинности из HttpContext.User в ASP.NET Core. Так состояние проверки подлинности интегрируется с существующими соответствующими механизмами проверки подлинности ASP.NET Core.

Важно!

Не используйте IHttpContextAccessor в Razor компонентах приложений Blazor Server . Приложения Blazor запускаются вне контекста конвейера ASP.NET Core. Не HttpContext гарантируется, что он будет доступен в IHttpContextAccessorи HttpContext не будет содержать контекст, запустив Blazor приложение. Дополнительные сведения см. в статье Влияние использования на IHttpContextAccessor безопасность в Blazor Server (dotnet/aspnetcore #45699). Дополнительные сведения о поддержании пользовательского состояния в приложениях см. в Blazor Server разделе управление состоянием ASP.NET CoreBlazor.

Дополнительные сведения о создании и настройке приложений см. в статье Защита приложений ASP.NET Core Blazor Server.

Служба AuthenticationStateProvider

AuthenticationStateProvider является базовой службой, которую компоненты AuthorizeView и CascadingAuthenticationState используют для получения состояния аутентификации.

Обычно вы не используете AuthenticationStateProvider напрямую. Выберите подход с использованием компонента AuthorizeView или Task<AuthenticationState>, как описано далее в этой статье. Основной недостаток при использовании AuthenticationStateProvider напрямую заключается в том, что компонент не получает автоматического уведомления при изменении базовых данных о состоянии аутентификации.

Служба AuthenticationStateProvider может предоставить данные ClaimsPrincipal о текущем пользователе, как показано в следующем примере:

@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>ClaimsPrincipal Data</h3>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Count() > 0)
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surnameMessage</p>

@code {
    private string authMessage;
    private string surnameMessage;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surnameMessage = 
                $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, а пользователь является ClaimsPrincipal, можно перечислить утверждения и оценить членство в ролях.

Дополнительные сведения о внедрении зависимостей и службах см. в статье Внедрение зависимостей ASP.NET Core Blazor и Внедрение зависимостей в ASP.NET Core. Сведения о реализации пользовательского поставщика AuthenticationStateProvider в приложениях Blazor Server см. в статье Защита приложений ASP.NET Core Blazor Server.

Предоставление состояния аутентификации в качестве каскадного параметра

Если процедурная логика требует данных о состоянии аутентификации, например при выполнении активируемых пользователем действий, для получения таких данных определите каскадный параметр типа Task<AuthenticationState>:

@page "/"

<button @onclick="LogUsername">Log username</button>

<p>@authMessage</p>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, можно перечислить утверждения и оценить членство в ролях.

Настройте каскадный параметр Task<AuthenticationState> с помощью компонентов AuthorizeRouteView и CascadingAuthenticationState в компоненте App (App.razor).

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Примечание

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

В приложении Blazor WebAssembly добавьте службы для параметров и авторизации в Program.cs:

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

В приложении Blazor Server уже есть службы для параметров и авторизации, поэтому ничего делать не нужно.

Авторизация

После аутентификации пользователя применяются правила авторизации, которые определяют доступные этому пользователю действия.

Доступ обычно предоставляется или запрещается в зависимости от следующих аспектов:

  • выполнена ли аутентификация (выполнен ли вход);
  • есть ли у пользователя определенная роль;
  • есть ли у пользователя определенное утверждение;
  • выполняются ли требования политики.

Каждый из этих аспектов применяется здесь так же, как в приложениях ASP.NET Core MVC или Razor Pages. Дополнительные сведения о безопасности в ASP.NET Core вы найдете в статьях о безопасности и Identity в ASP.NET Core.

Компонент AuthorizeView

Компонент AuthorizeView избирательно демонстрирует содержимое пользовательского интерфейса в зависимости от того, авторизован ли пользователь. Этот подход полезен, если вам нужно просто отображать пользователю данные, и не использовать удостоверение пользователя в процедурной логике.

Этот компонент представляет переменную context типа AuthenticationState, которую можно использовать для доступа к сведениям о пользователе, выполнившем вход:

<AuthorizeView>
    <h1>Hello, @context.User.Identity.Name!</h1>
    <p>You can only see this content if you're authenticated.</p>
</AuthorizeView>

Также вы можете указать другое содержимое, которое будет отображаться, если пользователь не авторизован:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authorized.</p>
        <button @onclick="SecureMethod">Authorized Only Button</button>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void SecureMethod() { ... }
}

Содержимое тегов <Authorized> и <NotAuthorized> может включать произвольные элементы, например другие интерактивные компоненты.

Обработчик событий по умолчанию для авторизованного элемента, например, метод SecureMethod для элемента <button> в предыдущем примере, может вызываться только авторизованным пользователем.

Условия авторизации, такие как роли или правила для выбора вариантов пользовательского интерфейса и доступа к ним, описаны в разделе об авторизации.

Если условия авторизации не указаны, AuthorizeView использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Компонент AuthorizeView можно использовать в компоненте NavMenu (Shared/NavMenu.razor) для отображения компонента NavLink (NavLink), но следует учитывать, что при использовании этого подхода удаляется только элемент списка из отображаемых выходных данных. Пользователь по-прежнему может переходить к компоненту.

Приложения, созданные на основе шаблона проекта Blazor, который включает проверку подлинности, используют компонент LoginDisplay, который зависит от компонента AuthorizeView. Компонент AuthorizeView выборочно отображает пользователям содержимое для операций, связанных с Identity. Следующий пример относится к шаблону проекта Blazor WebAssembly.

Shared/LoginDisplay.razor:

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code{
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Следующий пример относится к шаблону проекта Blazor Server и использует конечные точки ASP.NET Core Identity в области Identity приложения для обработки операций, связанных с Identity.

Shared/LoginDisplay.razor:

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Авторизация на основе ролей и политик

Компонент AuthorizeView поддерживает авторизацию на основе ролей или политик.

Для авторизации на основе ролей используйте Roles параметр . В следующем примере пользователь должен иметь утверждение роли для (или обеих) Admin ролей или Superuser :

<AuthorizeView Roles="Admin, Superuser">
    <p>You can only see this if you're an Admin or Superuser.</p>
</AuthorizeView>

Дополнительные сведения, включая инструкции по настройке, см. в статье Авторизация на основе ролей в ASP.NET Core.

Для авторизации на основе политик примените параметр Policy:

<AuthorizeView Policy="ContentEditor">
    <p>You can only see this if you satisfy the "ContentEditor" policy.</p>
</AuthorizeView>

Авторизация на основе утверждений считается особым случаем авторизации на основе политик. Например, вы можете определить политику, которая требует наличия определенного утверждения у пользователя. Дополнительные сведения см. в статье Авторизация на основе политик в ASP.NET Core.

Эти API-интерфейсы можно использовать в приложениях Blazor Server или Blazor WebAssembly.

Если не указано ни Roles, ни Policy, AuthorizeView использует политику по умолчанию.

Так как сравнение строк .NET по умолчанию учитывает регистр, соответствующие имена ролей и политик также чувствительны к регистру. Например, Admin (в верхнем регистре A) не рассматривается как роль admin (в нижнем регистре a).

Регистр Pascal обычно используется для имен ролей и политик (например, BillingAdministrator), но использование регистра Pascal не является строгим требованием. Разрешены различные схемы гильз, такие как верблюда, шашлык и змеиный корпус. Использование пробелов в именах ролей и политик также является необычным, но разрешенным. Например, billing administrator это необычный формат имени роли или политики в приложениях .NET, но допустимый.

Содержимое, отображаемое при асинхронной аутентификации

Blazor позволяет асинхронно определять состояние проверки подлинности. Основной сценарий для такого подхода — приложение Blazor WebAssembly, которое направляет запрос на проверку подлинности во внешнюю конечную точку.

Пока аутентификация выполняется, AuthorizeView по умолчанию не отображает содержимое. Для отображения содержимого в ходе проверки подлинности используйте тег <Authorizing>:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authenticated.</p>
    </Authorized>
    <Authorizing>
        <h1>Authentication in progress</h1>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

Такой подход обычно не применим к приложениям Blazor Server. Приложения Blazor Server узнают состояние проверки подлинности, как только оно устанавливается. Содержимое Authorizing можно указать в компоненте AuthorizeView для приложения Blazor Server, но это содержимое никогда не отображается.

Атрибут [Authorize]

Атрибут [Authorize] можно использовать в компонентах Razor:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Важно!

Используйте [Authorize] только для компонентов @page, полученных через маршрутизатор Blazor. Авторизация выполняется только как аспект маршрутизации и не для дочерних компонентов, которые отображаются на странице. Чтобы разрешить отображение конкретных частей на странице, используйте вместо этого AuthorizeView.

Атрибут [Authorize] также поддерживает авторизацию на основе ролей или политик. Для авторизации на основе ролей примените параметр Roles:

@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

Для авторизации на основе политик примените параметр Policy:

@page "/"
@attribute [Authorize(Policy = "ContentEditor")]

<p>You can only see this if you satisfy the 'ContentEditor' policy.</p>

Если не указано ни Roles, ни Policy, [Authorize] использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Авторизация ресурсов

Чтобы авторизовать пользователей для доступа к ресурсам, передайте данные маршрута запроса в параметр Resource в AuthorizeRouteView.

В содержимом Router.Found для запрошенного маршрута в компоненте App (App.razor):

<AuthorizeRouteView Resource="@routeData" RouteData="@routeData" 
    DefaultLayout="@typeof(MainLayout)" />

Дополнительные сведения о том, как данные состояния авторизации передаются и используются в процедурной логике, см. в статье Предоставление состояния аутентификации в качестве каскадного параметра.

Когда объект AuthorizeRouteView получает данные маршрута для ресурса, политики авторизации получают доступ к RouteData.PageType и RouteData.RouteValues, в результате чего разрешается использовать настраиваемую логику для принятия решений об авторизации.

В следующем примере в AuthorizationOptions создается политика EditUser для конфигурации службы авторизации приложения (AddAuthorizationCore) с помощью следующей логики:

  • Определение того, существует ли значение маршрута с ключом id. Если ключ существует, значение маршрута сохраняется в value.
  • В переменной с именем id сохраните value в виде строки или задайте пустое строковое значение (string.Empty).
  • Если id не является пустой строкой, следует подтвердить, что условия политики соблюдены (возвращается true), если значение строки начинается с EMP. В противном случае следует подтвердить, что политика завершается ошибкой (возвращается false).

В Program.cs или Startup.cs (в зависимости от модели размещения и версии платформы):

  • Добавьте пространства имен для Microsoft.AspNetCore.Components и System.Linq:

    using Microsoft.AspNetCore.Components;
    using System.Linq;
    
  • Добавьте политику:

    options.AddPolicy("EditUser", policy =>
        policy.RequireAssertion(context =>
        {
            if (context.Resource is RouteData rd)
            {
                var routeValue = rd.RouteValues.TryGetValue("id", out var value);
                var id = Convert.ToString(value, 
                    System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty;
    
                if (!string.IsNullOrEmpty(id))
                {
                    return id.StartsWith("EMP", StringComparison.InvariantCulture);
                }
            }
    
            return false;
        })
    );
    

Предыдущий пример — это упрощенная политика авторизации, используемая исключительно для демонстрации концепции с рабочим примером. Дополнительные сведения о создании и настройке политик авторизации см. в статье Авторизация на основе политик в ASP.NET Core.

В следующем компоненте EditUser ресурс в /users/{id}/edit имеет параметр маршрута для идентификатора пользователя ({id}). Компонент использует предыдущую политику авторизации EditUser, чтобы определить, будет ли значение маршрута id начинаться с EMP. Если id начинается с EMP, политика будет успешно применена, и доступ к компоненту будет разрешен. Если id начинается со значения, отличного от EMP, или если id является пустой строкой, то политика завершается ошибкой и компонент не загружается.

Pages/EditUser.razor:

@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]

<h1>Edit User</h1>

<p>The 'EditUser' policy is satisfied! <code>Id</code> starts with 'EMP'.</p>

@code {
    [Parameter]
    public string Id { get; set; }
}

Настройка несанкционированного содержимого для компонента маршрутизатора

Компонент Router вместе с компонентом AuthorizeRouteView позволяет приложению указать пользовательское содержимое для следующих ситуаций:

  • пользователь не удовлетворяет условию [Authorize], которое применено к компоненту Отображается разметка для элемента <NotAuthorized>. (атрибут [Authorize] описан в разделе Атрибут [Authorize]);
  • Выполняется асинхронная авторизация. Как правило, это означает, что выполняется проверка подлинности пользователя. Отображается разметка для элемента <Authorizing>.
  • Содержимое не найдено. Отображается разметка для элемента <NotFound>.

В компоненте App (App.razor):

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView ...>
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Примечание

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

Содержимое тегов <NotFound>, <NotAuthorized> и <Authorizing> может включать произвольные элементы, например другие интерактивные компоненты.

Если тег <NotAuthorized> не указан, то AuthorizeRouteView использует следующее резервное сообщение:

Not authorized.

Процедурная логика

Если приложению нужно проверять правила авторизации в составе процедурной логики, используйте каскадный параметр с типом Task<AuthenticationState>, чтобы получить ClaimsPrincipal пользователя. Task<AuthenticationState> можно комбинировать для оценки политик с другими службами, например IAuthorizationService.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the 
            // 'content-editor' policy.
        }
    }
}

Примечание

В компоненте приложения Blazor WebAssembly добавьте пространства имен Microsoft.AspNetCore.Authorization и Microsoft.AspNetCore.Components.Authorization:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

Эти пространства имен можно предоставить глобально, добавив их в файл _Imports.razor приложения.

Устранение неполадок

Распространенные ошибки

  • Для авторизации требуется каскадный параметр с типом Task<AuthenticationState>. Чтобы предоставить его, попробуйте использовать CascadingAuthenticationState.

  • Для authenticationStateTask возвращается значение null

Вполне вероятно, что проект не был создан на основе шаблона приложения Blazor Server с включенной проверкой подлинности. Примените <CascadingAuthenticationState> в качестве оболочки определенной части дерева пользовательского интерфейса, например в компоненте App (App.razor), следующим образом.

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

Примечание

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

CascadingAuthenticationState предоставляет каскадный параметр Task<AuthenticationState>, который он, в свою очередь, получает из базовой службы внедрения зависимостей AuthenticationStateProvider.

Дополнительные ресурсы

Сценарии безопасности для приложений Blazor Server и Blazor WebAssembly отличаются. Так как приложения Blazor Server выполняются на стороне сервера, проверки авторизации могут определить следующее:

  • параметры пользовательского интерфейса, предоставленные пользователю (например, какие пункты меню доступны пользователю);
  • правила доступа для приложений и компонентов.

Приложения Blazor WebAssembly выполняются на стороне клиента. В этом случае авторизация используется только для определения отображаемых вариантов пользовательского интерфейса. Так как пользователь может изменить или обойти проверки на стороне клиента, приложение Blazor WebAssembly не может применять правила авторизации доступа.

Соглашения об авторизации Razor Pages не применяются к маршрутизируемым компонентам Razor. Если компонент Razor, не поддерживающий маршрутизацию, встроен в страницу, соглашения об авторизации страницы оказывают косвенное влияние на компонент Razor, а также на остальную часть содержимого страницы.

Identity ASP.NET Core предназначена для работы в контексте обмена данными http-запросов и ответов, которые обычно не являются моделью взаимодействия между клиентом и сервером Blazor приложения. В приложениях ASP.NET Core, применяющих ASP.NET Core Identity для управления пользователями, следует использовать Razor Pages вместо компонентов Razor для пользовательского интерфейса, связанного с Identity, например для регистрации пользователей, входа, выхода и других задач управления пользователями.

Абстракции ASP.NET Core, например SignInManager<TUser> и UserManager<TUser>, не поддерживаются в компонентах Razor. Дополнительные сведения об использовании ASP.NET Core Identity с Blazor см. в Добавление шаблона ASP.NET Core Identity в приложение Blazor Server.

Проверка подлинности

Blazor использует существующие механизмы проверки подлинности ASP.NET Core для установления личности пользователя. Конкретный механизм зависит от того, как размещается приложение Blazor (Blazor WebAssembly или Blazor Server).

Blazor WebAssembly аутентификация

В приложениях Blazor WebAssembly проверку подлинности можно обойти, так как пользователь может изменять весь код на стороне клиента. Это же справедливо для всех технологий на стороне клиента, включая платформы одностраничного приложения JavaScript или собственных приложений для любой операционной системы.

Добавьте следующий код:

Вопросы обработки проверки подлинности и использования встроенной или настраиваемой службы AuthenticationStateProvider рассматриваются в следующих разделах.

Дополнительные сведения о создании приложений и конфигураций см. в статье Защита ASP.NET Core Blazor WebAssembly.

Blazor Server аутентификация

Приложения Blazor Server работают через подключение в реальном времени, созданное с помощью SignalR. Проверка подлинности в приложениях на основе SignalR выполняется при установлении подключения. Аутентификация может выполняться на основе cookie или других маркеров носителя.

Встроенная служба AuthenticationStateProvider для приложений Blazor Server получает данные о состоянии проверки подлинности из HttpContext.User в ASP.NET Core. Так состояние проверки подлинности интегрируется с существующими соответствующими механизмами проверки подлинности ASP.NET Core.

Важно!

Не используйте IHttpContextAccessor в Razor компонентах приложений Blazor Server . Приложения Blazor запускаются вне контекста конвейера ASP.NET Core. Не HttpContext гарантируется, что он будет доступен в IHttpContextAccessorи HttpContext не будет содержать контекст, запустив Blazor приложение. Дополнительные сведения см. в статье Влияние использования на IHttpContextAccessor безопасность в Blazor Server (dotnet/aspnetcore #45699). Дополнительные сведения о поддержании пользовательского состояния в приложениях см. в Blazor Server разделе управление состоянием ASP.NET CoreBlazor.

Дополнительные сведения о создании и настройке приложений см. в статье Защита приложений ASP.NET Core Blazor Server.

Служба AuthenticationStateProvider

AuthenticationStateProvider является базовой службой, которую компоненты AuthorizeView и CascadingAuthenticationState используют для получения состояния аутентификации.

Обычно вы не используете AuthenticationStateProvider напрямую. Выберите подход с использованием компонента AuthorizeView или Task<AuthenticationState>, как описано далее в этой статье. Основной недостаток при использовании AuthenticationStateProvider напрямую заключается в том, что компонент не получает автоматического уведомления при изменении базовых данных о состоянии аутентификации.

Служба AuthenticationStateProvider может предоставить данные ClaimsPrincipal о текущем пользователе, как показано в следующем примере:

@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>ClaimsPrincipal Data</h3>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Count() > 0)
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surnameMessage</p>

@code {
    private string authMessage;
    private string surnameMessage;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surnameMessage = 
                $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, а пользователь является ClaimsPrincipal, можно перечислить утверждения и оценить членство в ролях.

Дополнительные сведения о внедрении зависимостей и службах см. в статье Внедрение зависимостей ASP.NET Core Blazor и Внедрение зависимостей в ASP.NET Core. Сведения о реализации пользовательского поставщика AuthenticationStateProvider в приложениях Blazor Server см. в статье Защита приложений ASP.NET Core Blazor Server.

Предоставление состояния аутентификации в качестве каскадного параметра

Если процедурная логика требует данных о состоянии аутентификации, например при выполнении активируемых пользователем действий, для получения таких данных определите каскадный параметр типа Task<AuthenticationState>:

@page "/"

<button @onclick="LogUsername">Log username</button>

<p>@authMessage</p>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Если user.Identity.IsAuthenticated имеет значение true, можно перечислить утверждения и оценить членство в ролях.

Настройте каскадный параметр Task<AuthenticationState> с помощью компонентов AuthorizeRouteView и CascadingAuthenticationState в компоненте App (App.razor).

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

В приложении Blazor WebAssembly добавьте службы для параметров и авторизации в Program.cs:

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

В приложении Blazor Server уже есть службы для параметров и авторизации, поэтому ничего делать не нужно.

Авторизация

После аутентификации пользователя применяются правила авторизации, которые определяют доступные этому пользователю действия.

Доступ обычно предоставляется или запрещается в зависимости от следующих аспектов:

  • выполнена ли аутентификация (выполнен ли вход);
  • есть ли у пользователя определенная роль;
  • есть ли у пользователя определенное утверждение;
  • выполняются ли требования политики.

Каждый из этих аспектов применяется здесь так же, как в приложениях ASP.NET Core MVC или Razor Pages. Дополнительные сведения о безопасности в ASP.NET Core вы найдете в статьях о безопасности и Identity в ASP.NET Core.

Компонент AuthorizeView

Компонент AuthorizeView избирательно демонстрирует содержимое пользовательского интерфейса в зависимости от того, авторизован ли пользователь. Этот подход полезен, если вам нужно просто отображать пользователю данные, и не использовать удостоверение пользователя в процедурной логике.

Этот компонент представляет переменную context типа AuthenticationState, которую можно использовать для доступа к сведениям о пользователе, выполнившем вход:

<AuthorizeView>
    <h1>Hello, @context.User.Identity.Name!</h1>
    <p>You can only see this content if you're authenticated.</p>
</AuthorizeView>

Также вы можете указать другое содержимое, которое будет отображаться, если пользователь не авторизован:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authorized.</p>
        <button @onclick="SecureMethod">Authorized Only Button</button>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void SecureMethod() { ... }
}

Содержимое тегов <Authorized> и <NotAuthorized> может включать произвольные элементы, например другие интерактивные компоненты.

Обработчик событий по умолчанию для авторизованного элемента, например, метод SecureMethod для элемента <button> в предыдущем примере, может вызываться только авторизованным пользователем.

Условия авторизации, такие как роли или правила для выбора вариантов пользовательского интерфейса и доступа к ним, описаны в разделе об авторизации.

Если условия авторизации не указаны, AuthorizeView использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Компонент AuthorizeView можно использовать в компоненте NavMenu (Shared/NavMenu.razor) для отображения компонента NavLink (NavLink), но следует учитывать, что при использовании этого подхода удаляется только элемент списка из отображаемых выходных данных. Пользователь по-прежнему может переходить к компоненту.

Приложения, созданные на основе шаблона проекта Blazor, который включает проверку подлинности, используют компонент LoginDisplay, который зависит от компонента AuthorizeView. Компонент AuthorizeView выборочно отображает пользователям содержимое для операций, связанных с Identity. Следующий пример относится к шаблону проекта Blazor WebAssembly.

Shared/LoginDisplay.razor:

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code{
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Следующий пример относится к шаблону проекта Blazor Server и использует конечные точки ASP.NET Core Identity в области Identity приложения для обработки операций, связанных с Identity.

Shared/LoginDisplay.razor:

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Авторизация на основе ролей и политик

Компонент AuthorizeView поддерживает авторизацию на основе ролей или политик.

Для авторизации на основе ролей используйте Roles параметр . В следующем примере у пользователя должно быть утверждение роли для (или обеих) Admin ролей или Superuser :

<AuthorizeView Roles="Admin, Superuser">
    <p>You can only see this if you're an Admin or Superuser.</p>
</AuthorizeView>

Дополнительные сведения, включая инструкции по настройке, см. в статье Авторизация на основе ролей в ASP.NET Core.

Для авторизации на основе политик примените параметр Policy:

<AuthorizeView Policy="ContentEditor">
    <p>You can only see this if you satisfy the "ContentEditor" policy.</p>
</AuthorizeView>

Авторизация на основе утверждений считается особым случаем авторизации на основе политик. Например, вы можете определить политику, которая требует наличия определенного утверждения у пользователя. Дополнительные сведения см. в статье Авторизация на основе политик в ASP.NET Core.

Эти API-интерфейсы можно использовать в приложениях Blazor Server или Blazor WebAssembly.

Если не указано ни Roles, ни Policy, AuthorizeView использует политику по умолчанию.

Так как сравнение строк .NET по умолчанию учитывает регистр, соответствующие имена ролей и политик также чувствительны к регистру. Например, Admin (в верхнем регистреA) не рассматривается как роль admin ( строчная ).a

Регистр Pascal обычно используется для имен ролей и политик (например, BillingAdministrator), но использование регистра Pascal не является строгим требованием. Разрешены различные схемы насадки, такие как верблюда, кебаб и змеиный случай. Использование пробелов в именах ролей и политик также является необычным, но разрешенным. Например, billing administrator это необычный формат имени роли или политики в приложениях .NET, но допустимый.

Содержимое, отображаемое при асинхронной аутентификации

Blazor позволяет асинхронно определять состояние проверки подлинности. Основной сценарий для такого подхода — приложение Blazor WebAssembly, которое направляет запрос на проверку подлинности во внешнюю конечную точку.

Пока аутентификация выполняется, AuthorizeView по умолчанию не отображает содержимое. Для отображения содержимого в ходе проверки подлинности используйте тег <Authorizing>:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authenticated.</p>
    </Authorized>
    <Authorizing>
        <h1>Authentication in progress</h1>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

Такой подход обычно не применим к приложениям Blazor Server. Приложения Blazor Server узнают состояние проверки подлинности, как только оно устанавливается. Содержимое Authorizing можно указать в компоненте AuthorizeView для приложения Blazor Server, но это содержимое никогда не отображается.

Атрибут [Authorize]

Атрибут [Authorize] можно использовать в компонентах Razor:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Важно!

Используйте [Authorize] только для компонентов @page, полученных через маршрутизатор Blazor. Авторизация выполняется только как аспект маршрутизации и не для дочерних компонентов, которые отображаются на странице. Чтобы разрешить отображение конкретных частей на странице, используйте вместо этого AuthorizeView.

Атрибут [Authorize] также поддерживает авторизацию на основе ролей или политик. Для авторизации на основе ролей примените параметр Roles:

@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

Для авторизации на основе политик примените параметр Policy:

@page "/"
@attribute [Authorize(Policy = "ContentEditor")]

<p>You can only see this if you satisfy the 'ContentEditor' policy.</p>

Если не указано ни Roles, ни Policy, [Authorize] использует политику по умолчанию со следующими правилами:

  • выполнившие аутентификацию (выполнившие вход) пользователи считаются авторизованными;
  • не выполнившие аутентификацию (не выполнившие вход) пользователи считаются не авторизованными.

Настройка несанкционированного содержимого для компонента маршрутизатора

Компонент Router вместе с компонентом AuthorizeRouteView позволяет приложению указать пользовательское содержимое для следующих ситуаций:

  • пользователь не удовлетворяет условию [Authorize], которое применено к компоненту Отображается разметка для элемента <NotAuthorized>. (атрибут [Authorize] описан в разделе Атрибут [Authorize]);
  • Выполняется асинхронная авторизация. Как правило, это означает, что выполняется проверка подлинности пользователя. Отображается разметка для элемента <Authorizing>.
  • Содержимое не найдено. Отображается разметка для элемента <NotFound>.

В компоненте App (App.razor):

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView ...>
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView ...>
                ...
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Содержимое тегов <NotFound>, <NotAuthorized> и <Authorizing> может включать произвольные элементы, например другие интерактивные компоненты.

Если тег <NotAuthorized> не указан, то AuthorizeRouteView использует следующее резервное сообщение:

Not authorized.

Процедурная логика

Если приложению нужно проверять правила авторизации в составе процедурной логики, используйте каскадный параметр с типом Task<AuthenticationState>, чтобы получить ClaimsPrincipal пользователя. Task<AuthenticationState> можно комбинировать для оценки политик с другими службами, например IAuthorizationService.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the 
            // 'content-editor' policy.
        }
    }
}

Примечание

В компоненте приложения Blazor WebAssembly добавьте пространства имен Microsoft.AspNetCore.Authorization и Microsoft.AspNetCore.Components.Authorization:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

Эти пространства имен можно предоставить глобально, добавив их в файл _Imports.razor приложения.

Устранение неполадок

Распространенные ошибки

  • Для авторизации требуется каскадный параметр с типом Task<AuthenticationState>. Чтобы предоставить его, попробуйте использовать CascadingAuthenticationState.

  • Для authenticationStateTask возвращается значение null

Вполне вероятно, что проект не был создан на основе шаблона приложения Blazor Server с включенной проверкой подлинности. Примените <CascadingAuthenticationState> в качестве оболочки определенной части дерева пользовательского интерфейса, например в компоненте App (App.razor), следующим образом.

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

CascadingAuthenticationState предоставляет каскадный параметр Task<AuthenticationState>, который он, в свою очередь, получает из базовой службы внедрения зависимостей AuthenticationStateProvider.

Дополнительные ресурсы