很遗憾,在应用程序启动后,您无法修改应用于 MVC 的过滤器。
然而,MVC 有authorization requirements 的概念,它在每个请求上执行。这使他们成为您想要实现的目标的理想人选。
在高层次上,我们将:
- 更改默认授权策略以包含自定义要求;
- 创建处理这个要求的类,即判断是否满足
让我们创建需求类。它是空的,因为它不需要任何参数,因为结果将完全来自数据库:
public class ConditionalAnonymousAccessRequirement : IAuthorizationRequirement
{
}
然后我们创建处理这个需求的类:
public class ConditionalAnonymousAccessHandler : AuthorizationHandler<ConditionalAnonymousAccessRequirement>
{
private readonly AppDbContext _context;
public ConditionalAnonymousAccessHandler(AppDbContext context)
{
_context = context;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ConditionalAnonymousAccessRequirement requirement)
{
if (IsAnonymousAccessAllowed())
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
private bool IsAnonymousAccessAllowed()
{
// Implementation based on the value retrieved from the database
}
}
实现很简单。如果我们在数据库中发现允许匿名访问,我们将此要求标记为成功。如果满足策略中的至少一项要求,则整个策略成功。
下一步是将该要求添加到授权策略中。默认情况下,当使用不带参数的[Authorize] 属性时,MVC 使用默认授权策略,即just checks that the user is authenticated。让我们修改它以在 Startup 类的 ConfigureServices 方法中添加这个新要求:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddRequirements(new ConditionalAnonymousAccessRequirement())
.Build();
});
一切看起来都不错,但我们缺少最后一件。
虽然我们将需求添加到策略中,但我们还没有注册需求处理程序,is necessary for MVC to discover it。这又在ConfigureServices 方法中完成。
services.AddScoped<IAuthorizationHandler, ConditionalAnonymousAccessHandler>();
虽然文档显示处理程序已注册为单例,但在这种情况下,最好按 HTTP 请求注册它,因为它依赖于默认情况下按 HTTP 请求注册的 DbContext。将处理程序注册为单例意味着 DbContext 的实例将在整个应用程序生命周期内保持活动状态。
请告诉我你的进展如何!