Авторизация на основе ролей в ASP.NET Core MVC

Когда идентификация пользователя создается после проверки подлинности, пользователь может принадлежать к одной или нескольким ролям, что отражает различные полномочия, которые позволяют пользователю доступ к данным и выполнение операций. Например, Трейси может принадлежать ролям "Администратор" и "Пользователь" с доступом к административным веб-страницам в приложении, в то время как Скотт может принадлежать только роли "Пользователь" и не иметь доступа к административным данным или операциям. Создание и управление этими ролями зависит от резервного хранилища процесса авторизации. Роли становятся доступными для разработчика через ClaimsPrincipal.IsInRole. AddRoles необходимо вызвать для добавления ролевых служб при настройке системы идентификации приложения.

Хотя роли являются утверждениями, не все утверждения являются ролями. В зависимости от издателя удостоверений, роль может представлять собой собрание пользователей, которые могут использовать утверждения для членов группы, а также иметь собственное утверждение, связанное с идентификатором. Однако утверждения должны быть сведениями об отдельном пользователе. Использование ролей для добавления утверждений пользователю может запутать границу между пользователем и их отдельными утверждениями. Эта путаница заключается в том, что шаблоны одностраничных приложений (SPA) не предназначены для ролей. Кроме того, для организаций, которые переносят из локальной устаревшей системы, увеличение числа ролей за эти годы может означать, что запрос на роль может быть слишком большим, чтобы он помещался в токене, который можно использовать в SPA. Чтобы защитить СПА, см. статью "Используйте Identity для защиты серверной части веб-API для СПА".

В этой статье используются примеры MVC и основное внимание уделяется сценариям MVC. Для руководства по страницам Blazor и Razor смотрите в следующих ресурсах:

Добавьте службы ролей в Identity

Зарегистрируйте службы авторизации на основе ролей в файле Program, вызвав функцию AddRoles с типом роли в конфигурации приложения Identity. Тип роли в следующем примере:IdentityRole

builder.Services.AddDefaultIdentity<IdentityUser>( ... )
    .AddRoles<IdentityRole>()
    ...

Для предыдущего кода требуется пакет NuGet Майкрософт.AspNetCore.Identity.UI и директива using для Майкрософт.AspNetCore.Identity.

В случаях, когда приложение осуществляет детализированный контроль для сборки Identity вручную, вызовите AddRoles на AddIdentityCore.

builder.Services.AddIdentityCore<IdentityUser>()
    .AddRoles<IdentityRole>()
    ...

Зарегистрируйте службы авторизации на основе ролей в Startup.ConfigureServices (Startup.cs) путем вызова AddRoles с типом роли в конфигурации приложения Identity . Тип роли в следующем примере:IdentityRole

services.AddDefaultIdentity<IdentityUser>()
    .AddRoles<IdentityRole>()
    ...

Для предыдущего кода требуется пакет NuGet Майкрософт.AspNetCore.Identity.UI и директива using для Майкрософт.AspNetCore.Identity.

В случаях, когда приложение осуществляет детализированный контроль для сборки Identity вручную, вызовите AddRoles на AddIdentityCore.

services.AddIdentityCore<IdentityUser>()
    .AddRoles<IdentityRole>()
    ...

Проверки авторизации на основе ролей

Проверки авторизации на основе ролей:

  • Являются декларативными и указывают роли, в которых текущий пользователь должен состоять для доступа к запрошенному ресурсу.
  • Применяются к контроллерам или действиям в контроллере.

Например, следующий код ограничивает доступ к любым действиям на контроллере пользователям, которые являются членом Administrator роли:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
    ...
}

Несколько ролей можно указать как разделенный запятыми список. В следующем примере доступ ограничен пользователями, которые являются членами HRManager роли илиFinance роли:

[Authorize(Roles = "HRManager, Finance")]
public class SalaryController : Controller
{
    ...
}

При применении нескольких атрибутов пользователь должен быть членом всех указанных ролей. В следующем примере требуются обаPowerUserиControlPanelUser роли для вызова SetTime и Shutdown действий:

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
    public IActionResult SetTime() { ... }
    public IActionResult ShutDown() { ... }
}

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

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

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

На предыдущем контроллере:

  • К контроллеру и действию Administrator могут получить доступ члены роли PowerUser или роли SetTime.
  • Только члены роли Administrator могут получить доступ к действию ShutDown.

Контроллер можно защитить, но по-прежнему разрешить анонимный, не прошедший проверку подлинности доступ к отдельным действиям с атрибутом[AllowAnonymous]:

[Authorize]
public class Control3PanelController : Controller
{
    public IActionResult SetTime() { ... }

    [AllowAnonymous]
    public IActionResult Login() { ... }
}

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

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

Требования к роли можно выразить с помощью синтаксиса политики, где приложение регистрирует политику при запуске в рамках конфигурации службы авторизации. В следующем примере политика RequireAdministratorRole указывает, что все пользователи должны находиться в Administrator роли.

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("RequireAdministratorRole",
         policy => policy.RequireRole("Administrator"));

Политики применяются с помощью свойства Policy на атрибуте[Authorize]:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown() { ... }

В отличие от сопоставления ролей, которое обычно учитывает регистр, в ASP.NET Core поиск названия политики обычно не учитывает регистр, поэтому RequireAdministratorRole и requireadministratorrole ссылаются на ту же политику.

Чтобы указать несколько разрешенных ролей в требовании, укажите роли в качестве параметров метода RequireRole . В следующем примере пользователи авторизованы, если они принадлежат к ролям Administrator, PowerUser или BackupAdministrator.

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("ElevatedRights", policy =>
          policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));

Если вы хотите, чтобы политика требовала всех предыдущих ролей, свяжите роли с конструктором политики или укажите их в конструкторе политики отдельно в лямбда-выражении.

Привязано к построителю политик:

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("ElevatedRights", policy => 
        policy
            .RequireRole("Administrator")
            .RequireRole("PowerUser")
            .RequireRole("BackupAdministrator"));

Либо используйте лямбда-выражение:

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("ElevatedRights",
        policy =>
        {
            policy.RequireRole("Administrator");
            policy.RequireRole("PowerUser");
            policy.RequireRole("BackupAdministrator");
        });

Требования к роли можно выразить с помощью синтаксиса политики, где приложение регистрирует политику при запуске в рамках конфигурации службы авторизации. В следующем примере политика RequireAdministratorRole указывает, что все пользователи должны находиться в Administrator роли.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdministratorRole",
        policy => policy.RequireRole("Administrator"));
});

Политики применяются с помощью свойства Policy на атрибуте[Authorize]:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown() { ... }

Чтобы указать несколько разрешенных ролей в требовании, укажите роли в качестве параметров метода RequireRole . В следующем примере пользователи авторизованы, если они принадлежат к ролям Administrator, PowerUser или BackupAdministrator.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
        policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));
});

Если вы хотите, чтобы политика требовала всех предыдущих ролей, свяжите роли с конструктором политики или укажите их в конструкторе политики отдельно в лямбда-выражении.

Привязано к построителю политик:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
        policy
            .RequireRole("Administrator")
            .RequireRole("PowerUser")
            .RequireRole("BackupAdministrator"));
});

Либо используйте лямбда-выражение:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights",
        policy =>
        {
            policy.RequireRole("Administrator");
            policy.RequireRole("PowerUser");
            policy.RequireRole("BackupAdministrator");
        });
});

Требования к роли можно выразить с помощью синтаксиса политики, где приложение регистрирует политику при запуске в рамках конфигурации службы авторизации. В следующем примере политика RequireAdministratorRole указывает, что все пользователи должны находиться в Administrator роли.

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

Политики применяются с помощью свойства Policy на атрибуте[Authorize]:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown() { ... }

Чтобы указать несколько разрешенных ролей в требовании, укажите роли в качестве параметров метода RequireRole . В следующем примере пользователи авторизованы, если они принадлежат к ролям Administrator, PowerUser или BackupAdministrator.

services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
        policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));
});

Если вы хотите, чтобы политика требовала всех предыдущих ролей, свяжите роли с конструктором политики или укажите их в конструкторе политики отдельно в лямбда-выражении.

Привязано к построителю политик:

services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
        policy
            .RequireRole("Administrator")
            .RequireRole("PowerUser")
            .RequireRole("BackupAdministrator"));
});

Либо используйте лямбда-выражение:

services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights",
        policy =>
        {
            policy.RequireRole("Administrator");
            policy.RequireRole("PowerUser");
            policy.RequireRole("BackupAdministrator");
        });
});

Группы безопасности Windows-аутентификации в качестве ролей приложения

После настройки приложения для проверки подлинности Windows с клиентскими и серверными компьютерами, находящимися в одном домене Windows, группы безопасности пользователей автоматически включаются в качестве утверждений в ClaimsPrincipal пользователя.

User.Identity обычно является WindowsIdentity при использовании аутентификации Windows, и вы можете получить данные о группах SID или проверить, находится ли пользователь в роли, используя следующий код, где заполнитель {DOMAIN} — это домен, а {SID GROUP NAME} — это имя группы SID.

if (User.Identity is WindowsIdentity windowsIdentity)
{
    var groups = windowsIdentity.Groups;

    // If needed, obtain a list of the SID groups
    var securityGroups = 
        groups.Select(g => g.Translate(typeof(NTAccount)).ToString()).ToList();

    // If needed, obtain the user's Windows identity name
    var windowsIdentityName = windowsIdentity.Name;

    // Check if the user is in a specific SID group
    if (User.IsInRole(@"{DOMAIN}\{SID GROUP NAME}"))
    {
        // User is in the specified group
    }
    else
    {
        // User isn't in the specified group
    }
}
else
{
    // The user isn't authenticated with Windows Authentication
}

Демонстрацию связанного кода, который преобразует утверждения SID группы в удобочитаемые значения в приложении Blazor, см. компонент UserClaims в Secure ASP.NET Core Blazor Web App с проверкой подлинности Windows. Такой подход к получению утверждений группы SID можно объединить с добавлением утверждений, чтобы создать пользовательские утверждения роли при проверке подлинности пользователя.

Подход, аналогичный предыдущему примеру для получения утверждений группы безопасности, можно объединить с добавлением утверждений, используя IClaimsTransformation, для создания настраиваемых утверждений об уровне роли при проверке подлинности пользователя.

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