C# ASP.NET核心MVC ActionFilter在AuthorizationFilter之前执行

C# ASP.NET核心MVC ActionFilter在AuthorizationFilter之前执行,c#,asp.net-core,asp.net-core-mvc,action-filter,C#,Asp.net Core,Asp.net Core Mvc,Action Filter,在我的站点上,我有几个控制器,仅限于经过身份验证的用户。除此之外,还有一些控制器需要身份验证,也需要根据一年中的时间进行限制 为了处理这个问题,我创建了一个TimeRangeFilter-ActionFilter/ResourceFilter 下面是它的样子: public class TimeRangeFilter : Attribute, IActionFilter, IOrderedFilter { public string AllowedMonths { get; set; } /

在我的站点上,我有几个控制器,仅限于经过身份验证的用户。除此之外,还有一些控制器需要身份验证,也需要根据一年中的时间进行限制

为了处理这个问题,我创建了一个TimeRangeFilter-ActionFilter/ResourceFilter

下面是它的样子:

public class TimeRangeFilter : Attribute, IActionFilter, IOrderedFilter
{
  public string AllowedMonths { get; set; } // like |3|4|5|
  public string RedirectUrl { get; set; }
  ...... // OnActionExecuting....
}
然后,在我的控制器类上,我实现如下:

[TimeRangeFilter(AllowedMonths = "|3|4|", RedirectUrl = "/feature/welcome", Order = 1)]
[Authorize]
[IsNotNefarious]
public class HubController : BaseController
{...}
但是,即使过滤器上有IOrderedFilter接口,AuthorizationFilter也会先执行,然后执行my TimeRangeFilter

对于这个欢迎页面,我不想要求用户登录才能看到它。但是我不想在允许的月份内更改进入我的中心页面的URL


在授权筛选器执行之前,我如何确定要执行的ActionFilter/ResourceFilter的优先级,以及如何短路?

简短的回答是,您不能让ActionFilter在AuhtorizeFilter之前执行。但您可以将TimeRangeFilter转换为授权筛选器

public class TimeRangeFilterAttribute : Attribute, IAuthorizationFilter, IOrderedFilter
{
    public string AllowedMonths { get; set; } // like |3|4|5|
    public string RedirectUrl { get; set; }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (not allowed) {
            context.Result = new RedirectResult(RedirectUrl);
        }
    }
}

指定Order=0以使其在其他授权检查之前运行,或者尝试不为其实现IOrderedFilter,它也将首先执行。

来自@Alexander的解决方案不再适用于.NET Core 3.1;现在,Authorize属性正在AuthorizationMiddleware中进行评估,这是命中过滤器之前的许多步骤

最好的新方法是自己制作一个定制中间件,在用户外出后插入它;在启动时,让它手动查询端点信息。例如:

public class TimeRangeAttribute : Attribute {
    public string Info { get; set; }
}

public class TimeRangeMiddleware {
    private readonly RequestDelegate _next;
    public TimeRangeMiddleware(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context) {
        var endpoint = context.GetEndpoint();
        if (endpoint?.Metadata.GetMetadata<TimeRangeAttribute>() != null) {
            // check allowed or not
        }
        if(_next != null) await _next(context);
    }
}

// In Startup
public void Configure(...) {
    // ....
    app.UseRouting();
    app.UseMiddleware<TimeRangeMiddleware>();
    app.UseAuthentication();
    app.UseAuthorization();
    // ...
}

明白了,谢谢。所以,即使它使用了授权过滤器,我也不需要做任何类型的User.IsAuthenticated之类的事情……听起来不错!哦,快!谢谢你的评论。这是我的一个老问题,但我确实是在升级到ASP.NET核心3.1,并将在未来几周内发布。现在,我需要返回并确保/修复所有实现我的TimeRangeFilter的控制器。非常感谢。我投赞成票!我刚刚发现在3.1中有一个扩展方法可以更容易地获得端点,我更新了上面的代码。