您需要稍微使用一下该框架,因为您的全局策略比您要应用于特定控制器和操作的策略更严格:
- 默认情况下,只有 Admin 用户可以访问您的应用程序
- 还将授予特定角色访问某些控制器的权限(例如 UserManagers 访问
UsersController)
正如您已经注意到的,拥有全局过滤器意味着只有 Admin 用户可以访问控制器。当您在 UsersController 上添加附加属性时,只有 both Admin 和 UserManager 的用户将拥有访问。
可以使用与 MVC 5 类似的方法,但它的工作方式不同。
一种选择可能是重新创建您的 IsAdminOrAuthorizeAttribute,但这次是 AuthorizeFilter,然后您将添加为全局过滤器:
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 或自己的IApplicationModelConvention。两者都可以让您添加/删除特定的控制器和操作过滤器。
例如,您可以定义默认授权策略和额外的特定策略:
services.AddAuthorization(opts =>
{
opts.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().RequireRole("admin").Build();
opts.AddPolicy("Users", policy => policy.RequireAuthenticatedUser().RequireRole("admin", "users"));
});
然后您可以创建一个新的IApplicatioModelProvider,它将默认策略添加到没有自己的[Authorize] 属性的每个控制器(应用程序约定将非常相似,并且可能更符合框架的方式打算扩展。我只是快速使用现有的AuthorizationApplicationModelProvider作为指导):
public class OverridableDefaultAuthorizationApplicationModelProvider : IApplicationModelProvider
{
private readonly AuthorizationOptions _authorizationOptions;
public OverridableDefaultAuthorizationApplicationModelProvider(IOptions<AuthorizationOptions> authorizationOptionsAccessor)
{
_authorizationOptions = authorizationOptionsAccessor.Value;
}
public int Order
{
//It will be executed after AuthorizationApplicationModelProvider, which has order -990
get { return 0; }
}
public void OnProvidersExecuted(ApplicationModelProviderContext context)
{
foreach (var controllerModel in context.Result.Controllers)
{
if (controllerModel.Filters.OfType<IAsyncAuthorizationFilter>().FirstOrDefault() == null)
{
//default policy only used when there is no authorize filter in the controller
controllerModel.Filters.Add(new AuthorizeFilter(_authorizationOptions.DefaultPolicy));
}
}
}
public void OnProvidersExecuting(ApplicationModelProviderContext context)
{
//empty
}
}
//Register in Startup.ConfigureServices
services.TryAddEnumerable(
ServiceDescriptor.Transient<IApplicationModelProvider, OverridableDefaultAuthorizationApplicationModelProvider>());
有了这个,默认策略将在这 2 个控制器上使用:
public class FooController : Controller
[Authorize]
public class BarController : Controller
这里将使用特定的用户策略:
[Authorize(Policy = "Users")]
public class UsersController : Controller
请注意,您仍然需要为每个策略添加管理员角色,但至少您的所有策略都将在一个启动方法中声明。您可能可以创建自己的方法来构建始终添加管理员角色的策略。