Поделиться через


Пользовательские поставщики политик авторизации с помощью IAuthorizationPolicyProvider в ASP.NET Core

Автор: Майк Роусос (Mike Rousos)

Обычно при использовании авторизации на основе политик политики политики регистрируются путем вызова AuthorizationOptions.AddPolicy в рамках конфигурации службы авторизации. В некоторых сценариях может быть невозможно (или желательно) зарегистрировать все политики авторизации таким образом. В таких случаях можно использовать пользователь IAuthorizationPolicyProvider для управления предоставлением политик авторизации.

Примеры сценариев, в которых пользователь IAuthorizationPolicyProvider может оказаться полезным:

  • Использование внешней службы для оценки политики.
  • Использование большого диапазона политик (для разных номеров или возрастов), поэтому не имеет смысла добавлять каждую отдельную политику авторизации с вызовом AuthorizationOptions.AddPolicy .
  • Создание политик во время выполнения на основе информации во внешнем источнике данных (например, в базе данных) или динамическое определение требований авторизации с помощью другого механизма.

Просмотр или скачивание примера кода из репозитория GitHub AspNetCore. Скачайте ZIP-файл zip-файла репозитория dotnet/AspNetCore. Распакуйте файл . Перейдите в папку проекта src/Security/samples/CustomPolicyProvider .

Настройка извлечения политики

ASP.NET приложения Core используют реализацию IAuthorizationPolicyProvider интерфейса для получения политик авторизации. По умолчанию DefaultAuthorizationPolicyProvider регистрируется и используется. DefaultAuthorizationPolicyProvider возвращает политики из предоставленного AuthorizationOptions в вызове IServiceCollection.AddAuthorization .

Настройте это поведение, зарегистрируя другую IAuthorizationPolicyProvider реализацию в контейнере внедрения зависимостей приложения.

Интерфейс IAuthorizationPolicyProvider содержит три API:

  • GetPolicyAsync возвращает политику авторизации для заданного имени.
  • GetDefaultPolicyAsync возвращает политику авторизации по умолчанию (политика, используемая для [Authorize] атрибутов без указанной политики).
  • GetFallbackPolicyAsync возвращает резервную политику авторизации (политика, используемая ПО промежуточного слоя авторизации, если политика не указана).

Реализуя эти API, можно настроить способ предоставления политик авторизации.

Пример атрибута параметризованной авторизации

Один из сценариев, где IAuthorizationPolicyProvider полезно включить пользовательские [Authorize] атрибуты, требования которых зависят от параметра. Например, в документации по авторизации на основе политик в качестве примера использовалась политика на основе возраста (AtLeast21). Если различные действия контроллера в приложении должны быть доступны пользователям разных возрастов, может быть полезно иметь множество различных политик на основе возраста. Вместо регистрации всех разных политик на основе возраста, которые потребуется AuthorizationOptionsприложению, вы можете динамически создавать политики с помощью пользовательского IAuthorizationPolicyProvider. Чтобы упростить использование политик, можно произвести анимацию действий с помощью настраиваемого атрибута авторизации, например [MinimumAgeAuthorize(20)].

Настраиваемые атрибуты авторизации

Политики авторизации определяются своими именами. Ранее пользовательский пользователь MinimumAgeAuthorizeAttribute должен сопоставить аргументы с строкой, которую можно использовать для получения соответствующей политики авторизации. Это можно сделать, исходя из AuthorizeAttribute свойства и делая Age свойство оболочкой AuthorizeAttribute.Policy свойства.

internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute
{
    const string POLICY_PREFIX = "MinimumAge";

    public MinimumAgeAuthorizeAttribute(int age) => Age = age;

    // Get or set the Age property by manipulating the underlying Policy property
    public int Age
    {
        get
        {
            if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length), out var age))
            {
                return age;
            }
            return default(int);
        }
        set
        {
            Policy = $"{POLICY_PREFIX}{value.ToString()}";
        }
    }
}

Этот тип атрибута имеет Policy строку на основе жестко закодированного префикса ("MinimumAge") и целого числа, переданного через конструктор.

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

[MinimumAgeAuthorize(10)]
public IActionResult RequiresMinimumAge10()

Custom IAuthorizationPolicyProvider

Пользователь MinimumAgeAuthorizeAttribute позволяет легко запрашивать политики авторизации для любого требуемого возраста. Следующая проблема заключается в том, чтобы убедиться, что политики авторизации доступны для всех разных возрастов. Это место, где IAuthorizationPolicyProvider полезно.

При использовании MinimumAgeAuthorizationAttributeимена политик авторизации будут соответствовать шаблону "MinimumAge" + Age, поэтому пользователь IAuthorizationPolicyProvider должен создавать политики авторизации следующим образом:

  • Анализ возраста с имени политики.
  • Использование AuthorizationPolicyBuilder для создания нового AuthorizationPolicy
  • В этом и следующих примерах предполагается, что пользователь проходит проверку подлинности с помощью .cookie Должен AuthorizationPolicyBuilder быть создан по крайней мере с одним именем схемы авторизации или всегда выполнен успешно. В противном случае нет информации о том, как предоставить пользователю вызов, и будет создано исключение.
  • Добавление требований к политике в зависимости от возраста AuthorizationPolicyBuilder.AddRequirements. В других сценариях можно использовать RequireClaimили RequireRoleRequireUserName вместо этого.
internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider
{
    const string POLICY_PREFIX = "MinimumAge";

    // Policies are looked up by string name, so expect 'parameters' (like age)
    // to be embedded in the policy names. This is abstracted away from developers
    // by the more strongly-typed attributes derived from AuthorizeAttribute
    // (like [MinimumAgeAuthorize()] in this sample)
    public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
    {
        if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) &&
            int.TryParse(policyName.Substring(POLICY_PREFIX.Length), out var age))
        {
            var policy = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme);
            policy.AddRequirements(new MinimumAgeRequirement(age));
            return Task.FromResult(policy.Build());
        }

        return Task.FromResult<AuthorizationPolicy>(null);
    }
}

Несколько поставщиков политик авторизации

При использовании пользовательских IAuthorizationPolicyProvider реализаций следует учитывать, что ASP.NET Core использует только один экземпляр IAuthorizationPolicyProvider. Если настраиваемый поставщик не может предоставлять политики авторизации для всех используемых имен политик, он должен отложить поставщику резервных копий.

Например, рассмотрим приложение, которое нуждается как в пользовательских политиках возрастов, так и для получения более традиционных политик на основе ролей. Такое приложение может использовать настраиваемый поставщик политики авторизации, который:

  • Пытается проанализировать имена политик.
  • Вызывает другой поставщик политик (например DefaultAuthorizationPolicyProvider, если имя политики не содержит возраст).

Пример IAuthorizationPolicyProvider реализации, показанной выше, можно обновить для использования DefaultAuthorizationPolicyProvider путем создания поставщика политики резервного копирования в его конструкторе (если имя политики не соответствует ожидаемому шаблону "MinimumAge" + возраст).

private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; }

public MinimumAgePolicyProvider(IOptions<AuthorizationOptions> options)
{
    // ASP.NET Core only uses one authorization policy provider, so if the custom implementation
    // doesn't handle all policies it should fall back to an alternate provider.
    BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}

GetPolicyAsync Затем метод можно обновить, чтобы использовать BackupPolicyProvider вместо возвращающего значение NULL:

...
return BackupPolicyProvider.GetPolicyAsync(policyName);

Политика по умолчанию

Помимо предоставления именованных политик авторизации, пользователь IAuthorizationPolicyProvider должен реализовать GetDefaultPolicyAsync политику авторизации для [Authorize] атрибутов без указанного имени политики.

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

public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => 
    Task.FromResult(new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build());

Как и во всех аспектах пользовательского IAuthorizationPolicyProvider, вы можете настроить это, по мере необходимости. В некоторых случаях может потребоваться получить политику по умолчанию из резервной IAuthorizationPolicyProviderверсии.

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

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

Если резервная политика не требуется, поставщик может вернуть null или отложить резервный поставщик:

public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => 
    Task.FromResult<AuthorizationPolicy>(null);

Использование пользовательского IAuthorizationPolicyProvider

Чтобы использовать пользовательские политики из объектаIAuthorizationPolicyProvider, необходимо:

  • Зарегистрируйте соответствующие AuthorizationHandler типы с внедрением зависимостей (описано в авторизации на основе политик), как и во всех сценариях авторизации на основе политик.

  • Зарегистрируйте пользовательский IAuthorizationPolicyProvider тип в коллекции служб внедрения зависимостей приложения, Startup.ConfigureServices чтобы заменить поставщика политик по умолчанию.

    services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
    

Полный пользовательский IAuthorizationPolicyProvider пример доступен в репозитории dotnet/aspnetcore GitHub.