尝试在我的所有控制器中应用授权过滤器,但未使用 IAuthorizationHandler

Trying to apply an authorisation filter in all my controllers but IAuthorizationHandler is not being used

我尝试定义一个授权策略以应用于我所有控制器的所有方法。我正在尝试按照 guidelines given here, in "Authorization for specific endpoints" subsection 替换我之前的 AuthorizeFilter 但它不起作用。

在我的 Startup 我有:

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute().RequireAuthorization();
});

ConfigureServices中:

services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
    .AddAzureADBearer(options => this.Configuration.Bind("AzureAd", options));

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .AddRequirements(new MyRequirement(MyParams))
        .Build();
});
(...)
    services.AddTransient<IAuthorizationHandler, MyAuthorizationHandler>();

我有一个要求:

public class MyRequirement : IAuthorizationRequirement
{
    public EntityType MyParams { get; private set; }

    public MyRequirement(MyParams myParams) { MyParams = myParams; }
}

和一个处理程序:

public class MyAuthorizationHandler : AuthorizationHandler<MyRequirement>
{
    private readonly ILogger<MyAuthorizationHandler> logger;
    private readonly IHttpContextAccessor httpContextAccessor;

    public MyAuthorizationHandler(IHttpContextAccessor httpContextAccessor, ILogger<MyAuthorizationHandler> logger)
    {
        this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        this.logger = logger;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
    {
---> Some things. I don't get here when I debug.       
    }
}

在我的控制器中,我没有放置任何装饰器,因为我想将此授权策略应用于我的所有方法,这就是我覆盖 DefaultPolicy.

的原因

如果我调试,我不会像我预期的那样在处理程序处停止。实际上,如果我在控制器中放置一个装饰器 [Authorize],我确实会停在那里,但正如我提到的,我试图避免在所有控制器中编写这个装饰器。

为什么不起作用?谢谢!

我的理解是 [Authorize] 属性是使用默认策略所必需的。当我需要以这种方式保护我的所有端点时,我通常做的是创建一个具有此属性的抽象基控制器,然后让我的其他控制器继承它。

例如:

基地控制器

[Authorize]
public abstract class MyBaseController : Controller //use Controller for mvc controller or ControllerBase for api controller
{
//base controller methods and properties
}

其他控制器:

public class MyOtherController : MyBaseController 
{
//controller methods and properties
}

试试这个:

public void ConfigureServices(IServiceCollection services)
{         
    services.AddHttpContextAccessor();
    services.AddTransient<IAuthorizationHandler, MyAuthorizationHandler>();

    services.AddControllersWithViews(config =>
    {
        var policy = new AuthorizationPolicyBuilder()
                .AddRequirements(new MyRequirement(MyParams))
            .Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    });

    services.AddDbContext<MvcProj3Context>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("MvcProj3Context")));
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseAuthentication();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

    });
}

我终于解决了。在 ConfigureServicesstartup:

services.AddAuthorization(options =>
{
    options.AddPolicy(
        "UserIsRegistered",
        new AuthorizationPolicyBuilder()
            .AddRequirements(new RegistrationRequirement())
            .Build());
});

然后我定义了RegistrationRequirement:

 public class RegistrationRequirement : IAuthorizationRequirement
 {
 }

然后我定义了RegistrationAuthorizationHandler

public class RegistrationAuthorizationHandler : AuthorizationHandler<RegistrationRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RegistrationRequirement requirement)
        {
---> LOGIC I WANT TO CHECK
            if (WHATEVER)
            {
                context.Succeed(requirement);
            }
            return Task.CompletedTask;
        }
    } 

最后在 Configure 中又在 startup 中:

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

总而言之,我的主要问题是使用 MapDefaultControllerRoute 而不是 MapControllers...