ASP.NET 5 中的 OverrideAuthorizationAttribute

OverrideAuthorizationAttribute in ASP.NET 5

我想在 MVC6 中实现以下功能:

[Authorize(Roles = "Shopper")]
public class HomeController
{
    [Authorize(Roles = "Editor"), OverrideAuthorization]
    public IActionResult EditPage() {}
}

但 OverrideAuthorizationAttribute 已不存在。那么如何设置,让用户只需要处于 Editor 角色而不是 EditorShopper 角色就可以访问 MVC6 中的 EditPage?

我从 Filip W 那里找到了 this blog post,它解释了如何使用过滤器提供程序编写您自己的解决方案。

但是框架已经改变了很多,他的解决方案必须更新以考虑框架中的变化,直到 beta8

首先,您将创建一个新属性,您可以在其中指定要覆盖的 filter 的类型。 (在你的情况下,这将是 AuthorizeFilter

public class OverrideFilter : ActionFilterAttribute
{
    public Type Type { get; set; }
}

如果你愿意。您可以创建更具体的过滤器,例如:

public class OverrideAuthorization : OverrideFilter
{
    public OverrideAuthorization()
    {
        this.Type = typeof(AuthorizeFilter);
    }
}

然后你需要创建一个新的IFilterProvider

  1. 此过滤器提供程序将在默认提供程序之后执行 该框架有 运行.
  2. 您可以检查 FilterProviderContext.Results 并搜索您的 OverrideFilter
  3. 如果找到,您可以检查其余过滤器,然后删除 过滤类型和较低范围的任何过滤器

例如,按照这个想法创建一个新的 OverrideFriendlyFilterProvider

public class OverrideFriendlyFilterProvider : IFilterProvider
{
    //all framework providers have negative orders, so ours will come later
    public int Order => 1;

    public void OnProvidersExecuting(FilterProviderContext context)
    {
        if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
        {
            //Does the action have any OverrideFilter?
            var overrideFilters = context.Results.Where(filterItem => filterItem.Filter is OverrideFilter).ToArray();
            foreach (var overrideFilter in overrideFilters)
            {                    
                context.Results.RemoveAll(filterItem =>
                    //Remove any filter for the type indicated in the OverrideFilter attribute
                    filterItem.Descriptor.Filter.GetType() == ((OverrideFilter)overrideFilter.Filter).Type &&
                    //Remove filters with lower scope (ie controller) than the override filter (i.e. action method)
                    filterItem.Descriptor.Scope < overrideFilter.Descriptor.Scope);
            }
        }
    }

    public void OnProvidersExecuted(FilterProviderContext context)
    {
    }
}

您需要在您的启动 ConfigureServices 上注册它 class:

services.TryAddEnumerable(
    ServiceDescriptor.Singleton<IFilterProvider, OverrideFriendlyFilterProvider>());

通过所有这些,您将能够覆盖授权过滤器(或任何其他过滤器)。

例如,在新 mvc 应用程序的默认 HomeController 中,任何登录用户都可以访问 Home 操作,但只有具有管理员角色的用户才能访问能够访问 关于 操作:

[Authorize]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [Authorize(Roles = "admin"), OverrideAuthorization]
    public IActionResult About()
    {
        return View();
    }

我认为最好使用新的基于策略的授权方法而不是直接使用角色。

目前还没有很多关于基于策略的授权的文档,但this article是一个好的开始