【问题标题】:Asp.net Core code based policy needs access to Authorize attribute基于 Asp.net Core 代码的策略需要访问 Authorize 属性
【发布时间】:2017-03-15 18:08:31
【问题描述】:

在我的多租户应用程序中,每个租户都设置了用户权限(如果您更愿意,请阅读角色),因此我们向每个用户添加声明,其值为 TenantName权限.

我们正在使用基于策略的授权和使用以下代码的自定义代码

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class PermissionAuthorizeAttribute : AuthorizeAttribute
{
    public Permission[] AcceptedPermissions { get; set; }

    public PermissionAuthorizeAttribute()
    {

    }

    public PermissionAuthorizeAttribute(params Permission[] acceptedPermissions)
    {
        AcceptedPermissions = acceptedPermissions;
        Policy = "RequirePermission";
    }
}

public enum Permission
{
    Login = 1,
    AddUser = 2,
    EditOtherUser = 3,
    EditBaseData = 6,
    EditSettings = 7,
}

用上面的代码我们装饰控制器动作

[PermissionAuthorize(Permission.EditSettings)]
public IActionResult Index()

在 startup.cs 我们有

services.AddAuthorization(options =>
    {
        options.AddPolicy("RequirePermission", policy => policy.Requirements.Add(new PermissionRequirement()));
    });

在这种情况下,AuthorizationHandler 需要访问 PermissionAuthorizeAttribute,以便我们可以检查在操作上指定了哪些权限。目前我们可以通过以下代码获取属性,但我认为必须有更简单的方法,因为那里有很多强制转换。

public class PermissionRequirement : AuthorizationHandler<PermissionRequirement>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {

        var filters = ((FilterContext)context.Resource).Filters;

        PermissionAuthorizeAttribute permissionRequirement = null;
        foreach (var filter in filters)
        {
            var authorizeFilter = filter as AuthorizeFilter;
            if (authorizeFilter == null || authorizeFilter.AuthorizeData == null)
                continue;

            foreach (var item in authorizeFilter.AuthorizeData)
            {
                permissionRequirement = item as PermissionAuthorizeAttribute;
                if (permissionRequirement != null)
                    break;
            }

            if (permissionRequirement != null)
                break;
        }

        //TODO Check that the user has the required claims

        context.Succeed(requirement);
        return Task.CompletedTask;
    }
}

我找到的所有示例都是这样的,其中在 startup.cs 中指定了一些硬连线策略。 services.AddAuthorization(选项 => { options.AddPolicy("Over21", 政策 => policy.Requirements.Add(new MinimumAgeRequirement(21))); }

在这里你用

装饰你的控制器或动作
[Authorize(Policy="Over21")]
public class AlcoholPurchaseRequirementsController : Controller

我认为如果您可以像这样在控制器/动作中指定年龄,上面的示例会更好

[Authorize(Policy="OverAge", Age=21)]
public class AlcoholPurchaseRequirementsController : Controller

现在您需要为每个最低年龄添加不同的策略。

关于如何提高效率的任何想法?

【问题讨论】:

标签: security asp.net-core


【解决方案1】:

虽然我会使用Resource Based Authorization 评论,但有一种方法可以实现您的目标:

首先创建一个自定义属性:

public class AgeAuthorizeAttribute : Attribute
{
    public int Age{ get; set; }
    public AgeAuthorizeAttribute(int age)
    {
        Age = age;
    }
}

然后编写一个过滤器提供者:

public class CustomFilterProvider : IFilterProvider
{
    public int Order
    {
        get
        {
            return 0;
        }
    }

    public void OnProvidersExecuted(FilterProviderContext context)
    {
    }

    public void OnProvidersExecuting(FilterProviderContext context)
    {
        var ctrl = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
        var ageAttr = ctrl.MethodInfo.GetCustomAttribute<AgeAuthorizeAttribute>();
        if (ageAttr == null)
        {
             ageAttr = ctrl.ControllerTypeInfo.GetCustomAttribute<AgeAuthorizeAttribute>();
        }
        if (ageAttr != null)
        {
            var policy = new AuthorizationPolicyBuilder()
                   .AddRequirements(new MinimumAgeRequirement(ageAttr.Age))
                   .Build();

            var filter = new AuthorizeFilter(policy);
            context.Results.Add(new FilterItem(new FilterDescriptor(filter, FilterScope.Action), filter));
        }
    }
}

最后注册过滤器提供者:

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

并使用它

[AgeAuthorize(21)]
public IActionResult SomeAction()

... or
[AgeAuthorize(21)]
public class AlcoholPurchaseRequirementsController : Controller

ps:未测试

【讨论】:

  • 感谢您的意见。似乎获得实际属性的工作量大致相同,所以我想我会坚持我的代码。
猜你喜欢
  • 1970-01-01
  • 2017-03-31
  • 1970-01-01
  • 2023-03-16
  • 2018-12-28
  • 2021-11-07
  • 2020-10-05
  • 2020-03-01
  • 2016-09-13
相关资源
最近更新 更多