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}");
}
}
}
希望有用
这是关于 .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}");
}
}
}
希望有用