Об авторизации в веб-приложениях и микрослужбах .NET

Совет

Это содержимое является фрагментом из электронной книги, архитектуры микрослужб .NET для контейнерных приложений .NET, доступных в документации .NET или в виде бесплатного скачиваемого PDF-файла, который можно читать в автономном режиме.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

После проверки подлинности веб-API ASP.NET Core должны авторизовать доступ. Этот процесс позволяет службе предоставить интерфейсы API некоторым из пользователей, прошедших аутентификацию, но не всем. Авторизация может осуществляться на базе ролей пользователя или пользовательской политики, которая может включать требования к проверке или другую эвристику.

Чтобы ограничить доступ к маршруту ASP.NET Core MVC, достаточно просто применить атрибут Authorize к методу действия (или классу контроллера, если все действия контроллера требуют авторизации). Это показано в следующем примере:

public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    [Authorize]
    public ActionResult Logout()
    {
    }
}

По умолчанию при добавлении атрибута Authorize без параметров доступ к контроллеру или действию будет открыт только пользователям, прошедшим проверку подлинности. Если вы хотите предоставлять доступ к API более ограниченной группе пользователей, этот атрибут можно дополнить, указав определенные роли или правила.

Реализация авторизации на основе ролей

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

Если вы выполняете проверку подлинности с токенами носителя JWT, ПО промежуточного слоя ASP.NET Core JWT для проверки подлинности носителя запишет данные о ролях пользователя на основе утверждений роли из токена. Чтобы предоставить доступ к контролеру или действию MVC только пользователям с определенными ролями, включите параметр Roles в аннотацию Authorize, как показано в следующем фрагменте кода:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlPanelController : Controller
{
    public ActionResult SetTime()
    {
    }

    [Authorize(Roles = "Administrator")]
    public ActionResult ShutDown()
    {
    }
}

В этом примере только пользователи в роли Administrator или PowerUser могут получить доступ к API в контроллере панели управления (например, для выполнения действия SetTime). Доступ к API ShutDown будут иметь только пользователи в роли Administrator.

Если вы хотите, чтобы у пользователя было несколько ролей, используйте несколько атрибутов Authorize, как показано в примере:

[Authorize(Roles = "Administrator, PowerUser")]
[Authorize(Roles = "RemoteEmployee ")]
[Authorize(Policy = "CustomPolicy")]
public ActionResult API1 ()
{
}

В этом примере для вызова API1 пользователь должен:

  • иметь роль Administrator или PowerUser и

  • Иметь роль RemoteEmployee, и

  • Удовлетворять условиям пользовательского обработчика для авторизации в соответствии с политикой CustomPolicy.

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

Пользовательские правила авторизации могут быть записаны в виде политик авторизации. В этом разделе приводятся общие сведения. Дополнительные сведения см. в документации семинара по авторизации ASP.NET Core.

Пользовательские политики авторизации регистрируются в методе Startup.ConfigureServices с помощью метода service.AddAuthorization. Этот метод использует делегат, который настраивает аргумент AuthorizationOptions.

services.AddAuthorization(options =>
{
    options.AddPolicy("AdministratorsOnly", policy =>
        policy.RequireRole("Administrator"));

    options.AddPolicy("EmployeesOnly", policy =>
        policy.RequireClaim("EmployeeNumber"));

    options.AddPolicy("Over21", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(21)));
});

Как показано в примере, политики могут быть связаны с разными типами требований. После регистрации политики можно применять к действию или контроллеру, передавая имя политики в виде аргумента Policy в атрибуте Authorize (например, [Authorize(Policy="EmployeesOnly")]). У политик может быть сразу несколько требований (как показано в этих примерах).

В предыдущем примере первый вызов AddPolicy просто является альтернативным способом авторизации по ролям. Если применить [Authorize(Policy="AdministratorsOnly")] к API, доступ будут иметь только пользователи в роли Administrator.

Второй вызов AddPolicy демонстрирует простой способ потребовать определенное утверждение для пользователя. Метод RequireClaim также может принимать ожидаемые значения в качестве утверждения. Если значения указаны, требование удовлетворяется только в том случае, если пользователь одновременно имеет утверждение верного типа и одно из указанных значений. Если вы используете ПО промежуточного слоя для проверки подлинности носителей JWT, все свойства JWT будут доступны как утверждения пользователя.

Самая интересная политика показана в третьем методе AddPolicy, так как применяется пользовательское требование к авторизации. Используя пользовательские требования к авторизации, вы можете строго контролировать выполнение авторизации. Для этого необходимо реализовать следующие типы:

  • Тип Requirements, который является производным от IAuthorizationRequirement и содержит поля с указанием сведений о требовании. В примере это поле возраста с типом MinimumAgeRequirement.

  • Обработчик, применяющий AuthorizationHandler<TRequirement>, где T — это тип требования IAuthorizationRequirement, которое должен выполнить обработчик. Обработчик должен применить метод HandleRequirementAsync, который проверяет, удовлетворяет ли требованию заданный контекст, содержащий сведения о пользователе.

Если пользователь отвечает требованиям, вызов к context.Succeed будет указывать на авторизацию пользователя. Если пользователь может выполнить требования к авторизации несколькими способами, можно создать несколько обработчиков.

Вдобавок к регистрации пользовательских требований политики с вызовами AddPolicy вам также необходимо зарегистрировать обработчики пользовательских требований, внедрив зависимости (services.AddTransient<IAuthorizationHandler, MinimumAgeHandler>()).

Пример пользовательских требований к авторизации и обработчика для проверки возраста пользователя (на основе утверждения DateOfBirth) приводится в документации по авторизации для ASP.NET Core.

Авторизация и минимальные API

ASP.NET поддерживает минимальные API в качестве альтернативы API на основе контроллера. Политики авторизации — это рекомендуемый способ настройки авторизации для минимальных API, как показано в этом примере:

// Program.cs
builder.Services.AddAuthorizationBuilder()
  .AddPolicy("admin_greetings", policy =>
        policy
            .RequireRole("admin")
            .RequireScope("greetings_api"));

// build the app

app.MapGet("/hello", () => "Hello world!")
  .RequireAuthorization("admin_greetings");

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