IAuthorizationPolicyProvider: могу ли я использовать несколько поставщиков политики или мне нужно рассмотреть все случаи внутри одного поставщика общей политики? - PullRequest
0 голосов
/ 09 января 2020

В моей программе я хочу

  1. Проверить, зарегистрированы ли пользователи в таблице определенных пользователей для всех возможных действий.
  2. Только для определенных действий, Я также хочу проверить, есть ли у пользователя соответствующие права CRUD.

Я проверяю 1-е условие в startup с помощью следующего кода:

services.AddAuthorization(options =>
{
    // This policy checks if a user is registered in our Users table.
    options.AddPolicy(
        "UserIsRegistered",
        new AuthorizationPolicyBuilder()
            .AddRequirements(new RegistrationRequirement())
            .Build());
});

Я также добавляю

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireAuthorization("UserIsRegistered");
});

и определяю RegistrationRequirement и RegistrationAuthorizationHandler соответственно.

Для 2-го условия я создал атрибут CrudAuthorizeAttribute со своим CrudAuthorizationHandler. Поскольку для каждого возможного действия Crud у меня есть одна отдельная полиция, я создал CrudPolicyProvider.

Затем я зарегистрировал все в Startup:

services.AddTransient<IAuthorizationHandler, RegistrationAuthorizationHandler>();
services.AddTransient<IAuthorizationHandler, CrudAuthorizationHandler>();
services.AddTransient<IAuthorizationPolicyProvider, CrudPolicyProvider>();

Теперь я вижу, когда я проверяю 1-е условие Я получаю политику от CrudPolicyProvider, но я ожидаю, что этот генератор политик будет предоставлять политики только во 2-м условии.

Поэтому:

  • Есть ли способ укажите, что CrudPolicyProvider должен использоваться только с CrudAttribute и больше нигде?
  • В более общем смысле, можно ли определить двух поставщиков политики (как я могу сделать с IAuthorizationHandler)
services.AddTransient<IAuthorizationPolicyProvider, FirstPolicyProvider>();
services.AddTransient<IAuthorizationPolicyProvider, SecondPolicyProvider>();

и использовать каждый из них только при необходимости?

  • Если ответ нет , значит ли это, что я должен определить один GeneralPolicyProvider и внутри этот провайдер проверяет, какие политики я должен предоставлять каждый раз в зависимости от ситуации? (что-то вроде использования POLICY_PREFIX здесь ?).

Спасибо!

1 Ответ

1 голос
/ 10 января 2020

Могу ли я определить двух поставщиков политики (как я могу это сделать с IAuthorizationHandler) и использовать каждого из них только при необходимости

Вы можете. Но два отдельных поставщика политики не будут активированы соответственно. У вас может быть несколько поставщиков политики, но только один из них будет использоваться одновременно. Также нет волшебства c при использовании IAuthorizationPolicyProvider.

определить один GeneralPolicyProvider .... проверить, какие политики я должен предоставлять каждый раз в зависимости от ситуации, в которой я нахожусь? (что-то вроде использования POLICY_PREFIX здесь?).

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

Лучший способ - внедрить службу IHttpContextAccessor в GeneralPolicyProvider, так что вы можете проверить текущий EndPoint / HttpContext при запуске время, а затем вы можете динамически разрешить целевой поставщик политики .

Реализация выглядит следующим образом:

public class GenericPolicyProvider : IAuthorizationPolicyProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private AuthorizationOptions _authZOpts { get; }
    public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
    private IAuthorizationPolicyProvider _fstPolicyProvider  {get;set;}
    private IAuthorizationPolicyProvider _sndPolicyProvider  {get;set;}

    public GenericPolicyProvider(IHttpContextAccessor httpContextAccessor, IOptions<AuthorizationOptions> options)
    {
        this._httpContextAccessor = httpContextAccessor;
        this._authZOpts = options.Value;
        this.FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
        this._fstPolicyProvider = new FirstPolicyProvider(options.Value);
        this._sndPolicyProvider = new SecondPolicyProvider(options.Value);
    }

    // use the target provider to provide policy
    public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
    {
        var targetPolicyProvider = this.GetPolicyProvider(policyName);
        return targetPolicyProvider.GetPolicyAsync(policyName);
    }

    // get the target provider dynamically
    private IAuthorizationPolicyProvider GetPolicyProvider(string policyName)
    {

        var httpContext = this._httpContextAccessor.HttpContext;
        if(httpContext==null) throw new Exception("HttpContext must not be null");
        // now you get the HttpContext
        //    check HttpContext to determine which policy provider should be used
        // ...
        // or check endpoint,e.g. get a mark filter by endpoint.Metadata.GetMetadata<...>()
        var endpoint = httpContext.GetEndpoint();
        var someMarker = endpoint.Metadata.GetMetadata<SomeMarker>();
        // in short, resolve the policy provider dynamically:
        if(shouldUseFirstPolicyProvider())
            return this._fstPolicyProvider;
        else if(shouldUseSecondPolicyProvider())
            return this._sndPolicyProvider;
        else 
           return this.FallbackPolicyProvider;
    }
    ...
}

Наконец, не забудьте зарегистрировать этот GenericPolicyProvider при запуске.

...