DI 到 ASP.NET MVC 6 中的 Requirement/Policy

DI into a Requirement/Policy in ASP.NET MVC 6

我正在寻找一种在 ASP.NET 5 中编写自定义授权过滤器的方法,因为当前的实现依赖于 Policies/Requirements,而后者又完全依赖于声明的使用,因此依赖于无数个不断变化的身份系统,我真的很厌倦(我已经尝试过所有的口味)。

我有一大组权限(超过 200 个),我不想将其编码为声明,因为我有自己的存储库,并且比比较数百个字符串更快地检查它(这就是最终的主张。

我需要在每个属性中传递一个参数,该参数应根据我的自定义权限存储库进行检查:

[Authorize(Requires = enumPermission.DeleteCustomer)]

我知道这不是最常见的情况,但我认为这不是边缘情况。我已经尝试按照@leastprivilege 在他宏伟的 post “ASP.NET 5 和 MVC 6 中的安全状态:授权”中描述的方式来实现它,但我遇到了与作者,他甚至在 ASP.NET 5 github 回购协议上提出了一个问题,该问题已以不太明确的方式关闭:link

知道如何实现吗?也许使用其他类型的过滤器?那怎么办呢?

以下是如何实现此场景的示例:

假设您有一个名为 IPermissionStore 的服务,它会验证给定用户是否具有在属性上指定的所需权限。

public class MyCustomAuthorizationFilterAttribute : Attribute, IFilterFactory, IOrderedFilter
{
    private readonly Permision[] _permissions;

    public MyCustomAuthorizationFilterAttribute(params Permision[] permissions)
    {
        _permissions = permissions;
    }

    public int Order { get; set; }

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        var store = serviceProvider.GetRequiredService<IPermissionStore>();

        return new MyCustomAuthorizationFilter(store, _permissions)
        {
            Order = Order
        };
    }
}

public class MyCustomAuthorizationFilter : IAuthorizationFilter, IOrderedFilter
{
    private readonly IPermissionStore _store;
    private readonly Permision[] _permissions;

    public int Order { get; set; }

    public MyCustomAuthorizationFilter(IPermissionStore store, params Permision[] permissions)
    {
        _store = store;
        _permissions = permissions;
    }

    public void OnAuthorization(AuthorizationContext context)
    {
        // Check if the action has an AllowAnonymous filter
        if (!HasAllowAnonymous(context))
        {
            var user = context.HttpContext.User;
            var userIsAnonymous =
                user == null ||
                user.Identity == null ||
                !user.Identity.IsAuthenticated;

            if (userIsAnonymous)
            {
                Fail(context);
            }
            else
            {
                // check the store for permissions for the current user
            }
        }
    }

    private bool HasAllowAnonymous(AuthorizationContext context)
    {
        return context.Filters.Any(item => item is Microsoft.AspNet.Authorization.IAllowAnonymous);
    }

    private void Fail(AuthorizationContext context)
    {
        context.Result = new HttpUnauthorizedResult();
    }
}

// Your action
[HttpGet]
[MyCustomAuthorizationFilter(Permision.CreateCustomer)]
public IEnumerable<string> Get()
{
    //blah
}