C# .NET Core 为自定义方法属性设置默认值

C# .NET Core Set a default for custom method attributes

这是关于 .NET Core MVC API 应用程序。

我定义了一个检查用户角色的自定义属性。我现在必须将其作为属性添加到我的所有方法中,以确保令牌具有正确的声明。

我如何为此设置默认值,以便不必将此属性添加到所有方法?如果我忘记添加它,它应该承担最高角色,因此权限较低的用户将被拒绝访问。

例如:

[Role(UserRole.ADMIN)]
public getAllUsers()  {} // As ADMIN is the highest role only admins can access

[Role(UserRole.CLIENT)]
public getMyData() { } // As CLIENT is the lowest role, everyone can access

public getStatistics() { } // As I forgot to set the attribute, only admins should be able to access

更新:

应要求,我的属性class。我认为它相对简单,但是为了检查权限,它完成了工作:

    public class RoleAttribute : TypeFilterAttribute
    {
        public RoleAttribute(UserRole role) : base(typeof(RoleFilter)) { 
            Arguments = new object[] { role };
        }
    }

    public class RoleFilter : IAuthorizationFilter
    {
        readonly UserRole role;

        public RoleFilter(UserRole role)
        {
            this.role = role;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {

            var hasRole = context.HttpContext.User.Claims.Any(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" && (int)Enum.Parse(typeof(UserRole), x.Value) <= (int)role);
            if (!hasRole)
            {
                context.Result = new ForbidResult();
            }
        }
    }

更新 2

使用构造函数没有帮助。

有了这个:

public RoleAttribute(UserRole role = UserRole.ADMIN) : base(typeof(RoleFilter)) { 

我至少还要补充一下:

[Role()]
public getStatistics() { } 

但我想完成(没有任何属性):

public getStatistics() { } 

对于任何想要完成同样的事情的人:

此问题已通过创建在每次构建后运行的单元测试来解决。它不会实现属性不存在的可能性,而是强制其存在。

测试归结为:

  • 正在检索所有控制器
  • 迭代控制器并检查它们是否包含 RoleAttribute
  • 如果没有,则获取控制器的所有方法
  • 检查方法是否包含 RoleAttribute 或 AllowAnonymousAttribute

所以:

[TestMethod]
public void CheckExistenceOfRoleAttributeDecorator()
{
    var types = typeof(Startup).Assembly.GetTypes();
    var controllers = types.Where(t => t.IsSubclassOf(typeof(ControllerBase)) && !t.IsAbstract);
    foreach (var controller in controllers)
    {
        if (!controller.GetCustomAttributes(typeof(RoleAttribute), true).Any())
        {
            var actions = controller.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public);
            foreach (var action in actions)
            {
                Assert.IsTrue(action.GetCustomAttributes(typeof(RoleAttribute), true).Any() || action.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any(), $"Attribute Role and AllowAnonymous not found on {controller.Name}.{action.Name}. Either one of those should be present.");
            }
        }
        else
        { 
            // This assert is always true because of the condition above, but added for readability of the logic.
            Assert.IsTrue(controller.GetCustomAttributes(typeof(RoleAttribute), true).Any(), $"Attribute Role not found on {controller.FullName}");
        }
    }
}

希望有用