C# 重写ASP.NET Core 1.0 MVC中的全局授权筛选器
我正在尝试在ASP.NET Core 1.0(MVC 6)web应用程序中设置授权 更严格的方法-默认情况下,我希望将所有控制器和操作方法限制为具有C# 重写ASP.NET Core 1.0 MVC中的全局授权筛选器,c#,asp.net-core,asp.net-core-mvc,asp.net-core-1.0,C#,Asp.net Core,Asp.net Core Mvc,Asp.net Core 1.0,我正在尝试在ASP.NET Core 1.0(MVC 6)web应用程序中设置授权 更严格的方法-默认情况下,我希望将所有控制器和操作方法限制为具有Admin角色的用户。因此,我添加了一个全局授权属性,如: AuthorizationPolicyRequiredMinRole=new AuthorizationPolicyBuilder() .RequireAuthenticatedUser()文件 .RequireRole(“管理员”) .Build(); services.AddMvc(op
Admin
角色的用户。因此,我添加了一个全局授权属性,如:
AuthorizationPolicyRequiredMinRole=new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()文件
.RequireRole(“管理员”)
.Build();
services.AddMvc(options=>{options.Filters.Add(newauthorizefilter(requiredminrole));});
然后我想允许具有特定角色的用户访问具体的控制器。例如:
[Authorize(Roles=“Admin,UserManager”)]
公共类UserController:控制器{}
这当然不起作用,因为“全局过滤器”不允许UserManager
访问控制器,因为他们不是“管理员”
在MVC5中,我可以通过创建一个自定义的authorize属性并将逻辑放在那里来实现这一点。然后将此自定义属性用作全局属性。例如:
公共类IsAdminOrAuthorizeAttribute:AuthorizeAttribute
{
授权时的公共覆盖无效(AuthorizationContext filterContext)
{
ActionDescriptor action=filterContext.ActionDescriptor;
if(action.IsDefined(typeof(AuthorizeAttribute),true)||
action.ControllerDescriptor.IsDefined(typeof(AuthorizeAttribute),true))
{
返回;
}
基于授权(filterContext);
}
}
我试图创建一个自定义的授权过滤器
,但没有成功。API似乎有所不同
所以我的问题是:是否可以设置默认策略,然后为特定的控制器和操作覆盖它。或者类似的东西。
我不想这样做
[Authorize(Roles=“Admin,[OtherRoles]”)
在每个控制器/操作上,因为这是一个潜在的安全问题。如果我不小心忘记了设置
管理员
角色,会发生什么情况。由于您的全局策略比您希望应用于特定控制器和操作的策略更具限制性,因此您需要稍微使用该框架:
- 默认情况下,只有管理员用户可以访问您的应用程序
- 还将授予特定角色对某些控制器的访问权限(例如用户管理器访问
)userscocontroller
userscoontroller
上添加附加属性时,只有管理员和用户管理器的用户才具有访问权限
可以使用与MVC5类似的方法,但工作方式不同
- 在MVC6中,该属性不包含授权逻辑
- 相反,它具有一个调用授权服务以确保满足策略的
方法李>OnAuthorizeAsync
- 特定属性用于为每个具有
属性的控制器和操作添加[Authorize]
AuthorizeFilter
一个选项是重新创建您的
isAdminorAuthorizationAttribute
,但这次是作为AuthorizationFilter
添加为全局筛选器:
public class IsAdminOrAuthorizeFilter : AuthorizeFilter
{
public IsAdminOrAuthorizeFilter(AuthorizationPolicy policy): base(policy)
{
}
public override Task OnAuthorizationAsync(Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext context)
{
// If there is another authorize filter, do nothing
if (context.Filters.Any(item => item is IAsyncAuthorizationFilter && item != this))
{
return Task.FromResult(0);
}
//Otherwise apply this policy
return base.OnAuthorizationAsync(context);
}
}
services.AddMvc(opts =>
{
opts.Filters.Add(new IsAdminOrAuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("admin").Build()));
});
这将仅在控制器/操作没有特定的[Authorize]
属性时应用全局筛选器
您还可以通过在生成过滤器的过程中注入自己来避免使用全局过滤器,该过滤器将应用于每个控制器和操作。您可以添加自己的
IApplicationModelProvider
或自己的iApplicationModelConversation
。两者都允许您添加/删除特定的控制器和操作过滤器
例如,您可以定义默认授权策略和额外的特定策略:
services.AddAuthorization(opts =>
{
opts.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().RequireRole("admin").Build();
opts.AddPolicy("Users", policy => policy.RequireAuthenticatedUser().RequireRole("admin", "users"));
});
然后,您可以创建一个新的iaapplicationmodelprovider
,将默认策略添加到每个没有自己的[Authorize]
属性的控制器(应用程序约定将非常类似,并且可能更符合框架的扩展方式。我只是快速使用了现有的AuthorizationApplicationModelProvider
):
此处将使用特定的用户策略:
[Authorize(Policy = "Users")]
public class UsersController : Controller
请注意,您仍然需要将管理员角色添加到每个策略中,但至少您的所有策略都将在一个启动方法中声明。您可以创建自己的方法来构建始终添加管理员角色的策略。使用@Daniel的解决方案,我遇到了@TarkaDaal在评论中提到的相同问题(每个调用的上下文中都有2个
AuthorizeFilter
,不太确定它们来自哪里)
因此,我的解决方法如下:
public class IsAdminOrAuthorizeFilter : AuthorizeFilter
{
public IsAdminOrAuthorizeFilter(AuthorizationPolicy policy): base(policy)
{
}
public override Task OnAuthorizationAsync(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
{
if (context.Filters.Any(f =>
{
var filter = f as AuthorizeFilter;
//There's 2 default Authorize filter in the context for some reason...so we need to filter out the empty ones
return filter?.AuthorizeData != null && filter.AuthorizeData.Any() && f != this;
}))
{
return Task.FromResult(0);
}
//Otherwise apply this policy
return base.OnAuthorizationAsync(context);
}
}
services.AddMvc(opts =>
{
opts.Filters.Add(new IsAdminOrAuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("admin").Build()));
});
这很难看,但在这种情况下它是有效的,因为如果您只使用Authorize属性,而不使用任何参数,那么您将由
newauthorizationpolicybuilder().RequireRole(“admin”).Build()处理
无论如何都要过滤。哈,谢谢你的详细解释。这正是我想要实现的。我知道我可以覆盖AuthorizeFilter
,但只是没有付出足够的努力。对于iaapplicationmodelprovider
,我不知道。只是实现了iaapplicationmodelprovider
方法我认为它更符合新MVC auth模型的精神,所以我会继续使用它。我还会尝试一下iaApplicationModelConversation
,甚至可以在服务中添加它们。AddMvc()
扩展方法。关于代码的主要区别在于,您需要以某种方式将身份验证选项传递给它。这对我不起作用。我正在尝试过滤方法,在OnAuthorizationAsy中
[Authorize(Policy = "Users")]
public class UsersController : Controller
public class IsAdminOrAuthorizeFilter : AuthorizeFilter
{
public IsAdminOrAuthorizeFilter(AuthorizationPolicy policy): base(policy)
{
}
public override Task OnAuthorizationAsync(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
{
if (context.Filters.Any(f =>
{
var filter = f as AuthorizeFilter;
//There's 2 default Authorize filter in the context for some reason...so we need to filter out the empty ones
return filter?.AuthorizeData != null && filter.AuthorizeData.Any() && f != this;
}))
{
return Task.FromResult(0);
}
//Otherwise apply this policy
return base.OnAuthorizationAsync(context);
}
}
services.AddMvc(opts =>
{
opts.Filters.Add(new IsAdminOrAuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("admin").Build()));
});