Пользовательская политика авторизации с несколькими требованиями, не работающая при применении к действию контроллера

#asp.net-core #asp.net-core-webapi #authorize-attribute

#asp.net-ядро #asp.net-core-webapi #authorize-атрибут

Вопрос:

У меня есть .NET Core 3 WebAPI, где я хочу использовать пользовательскую авторизацию на основе политик, где одна из политик имеет несколько требований.

Я добавил политику в Startup.ConfigureServices() и добавил MyCustomPolicyHandler в DI:

 public virtual void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy("MyCustomPolicy", policy =>
        {
            policy.Requirements.Add(new RequirementA());
            policy.Requirements.Add(new RequirementB());
            policy.Requirements.Add(new RequirementC());
            policy.Requirements.Add(new RequirementD());
            
        });
        
        services.AddScoped<IAuthorizationHandler, MyCustomPolicyHandler>();
        
    });                
}
  

Я реализовал MyCustomPolicyHandler , используя пример из этой документации:
Авторизация на основе политики в ASP.NET Ядро

 public class MyCustomPolicyHandler: IAuthorizationHandler
{

    public Task HandleAsync(AuthorizationHandlerContext context)
    {
    
        var pendingRequirements = context.PendingRequirements.ToList();         
        
        Console.WriteLine($"MyCustomPolicyHandler: {pendingRequirements.Count} requirements");
        
        foreach (var requirement in pendingRequirements)
        {
            if(requirement is RequirementA) {
            
                // do stuff to check the requirements
                context.Succeed(requirement);
                
            }
            else if(requirement is RequirementB) {
                
                // do stuff to check the requirements
                context.Succeed(requirement);
            
            }
            else if(requirement is RequirementC) {
            
                // do stuff to check the requirements
                context.Succeed(requirement);
                
            }
            else if(requirement is RequirementD) {
                
                // do stuff to check the requirements
                context.Succeed(requirement);
            
            }
        }
        
        return Task.CompletedTask;
    
    }
}
  

Затем я применяю политику к одному из действий контроллера:

 public class MyController 
{
    [HttpGet]
    [Authorize(Policy="MyCustomPolicy")]    
    public ActionResult<SomeViewModel> Get(int id) {
    
        // do stuff
        
        return Ok(vm);
    }

}
  

Проблема, с которой я сталкиваюсь, заключается в отсутствии требований, связанных с политикой. В Console.WriteLine() сообщении отображается 0 требований:

 MyCustomPolicyHandler: 0 requirements
  

Если я перенесу политику на контроллер, требования будут присутствовать:

 [Authorize(Policy="MyCustomPolicy")]
public class MyController 
{
    [HttpGet]
    public ActionResult<SomeViewModel> Get(int id) {
    
        // do stuff
        
        return Ok(vm);
    }

}
  
 MyCustomPolicyHandler: 4 requirements
  

Однако мне нужно, чтобы эта политика применялась к действию, а не к контроллеру. Атрибут [Authorize(Policy=»MyCustomPolicy»)] должен работать на уровне действия.

Есть идеи, почему это не работает?

Спасибо.

Ответ №1:

Потому что место, куда MyCustomPolicyHandler вводится, неуместно. Его необходимо поместить вне AddAuthorization .

 services.AddAuthorization(options =>
{
     options.AddPolicy("MyCustomPolicy", policy =>
     {
         policy.Requirements.Add(new RequirementA());
         //...
     });          
});

services.AddScoped<IAuthorizationHandler, MyCustomPolicyHandler>();
  

Результат:
введите описание изображения здесь

Комментарии:

1. хороший улов! Не могли бы вы показать мне, где вы применили политику (к контроллеру или действию?). К сожалению, я все еще показываю pendingRequirements = 0 .

2. Я поместил политику в действие.