覆盖ASP.NET Core 1.0 MVC中的全局授权过滤器

reg*_*uld 25 c# asp.net-core-mvc asp.net-core asp.net-core-1.0

我试图在ASP.NET Core 1.0(MVC 6)Web应用程序中设置授权.

更严格的方法 - 默认情况下,我希望将所有控制器和操作方法限制为具有Admin角色的用户.所以,我正在添加一个全局授权属性,如:

AuthorizationPolicy requireAdminRole = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .RequireRole("Admin")
    .Build();
services.AddMvc(options => { options.Filters.Add(new AuthorizeFilter(requireAdminRole));});
Run Code Online (Sandbox Code Playgroud)

然后我想允许具有特定角色的用户访问具体的控制器.例如:

[Authorize(Roles="Admin,UserManager")]
public class UserControler : Controller{}
Run Code Online (Sandbox Code Playgroud)

这当然是行不通的,因为"全局过滤器"不允许UserManager访问控制器,因为它们不是"管理员".

在MVC5中,我能够通过创建自定义授权属性并将我的逻辑放在那里来实现这一点.然后使用此自定义属性作为全局.例如:

public class IsAdminOrAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        ActionDescriptor action = filterContext.ActionDescriptor;
        if (action.IsDefined(typeof(AuthorizeAttribute), true) ||
            action.ControllerDescriptor.IsDefined(typeof(AuthorizeAttribute), true))
        {
            return;
        }

        base.OnAuthorization(filterContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图创建一个自定义AuthorizeFilter,但没有成功.API似乎有所不同.

所以我的问题是:是否可以设置默认策略,然后为特定控制器和操作覆盖它.或类似的东西.我不想这样做

[Authorize(Roles="Admin,[OtherRoles]")]
Run Code Online (Sandbox Code Playgroud)

在每个控制器/操作上,因为这是一个潜在的安全问题.如果我不小心忘记了这个Admin角色会发生什么.

Dan*_*.G. 35

您需要稍微使用框架,因为您的全局策略比您想要应用于特定控制器和操作的策略更具限制性:

  • 默认情况下,仅管理员用户可以访问您的应用
  • 特定角色也将被授予对某些控制器的访问权限(如访问的UserManagersUsersController)

正如您已经注意到的那样,拥有全局过滤器意味着只有Admin用户才能访问控制器.当您添加的附加属性UsersController,只有那些用户 管理员 的UserManager将有机会获得.

可以使用与MVC 5类似的方法,但它以不同的方式工作.

  • 在MVC 6中,该[Authorize]属性不包含授权逻辑.
  • 而是AuthorizeFilter具有OnAuthorizeAsync调用授权服务以确保满足策略的方法的那个.
  • 特定IApplicationModelProvider用于AuthorizeFilter为每个具有[Authorize]属性的控制器和操作添加一个.

一个选项可能是重新创建您的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()));
});
Run Code Online (Sandbox Code Playgroud)

仅当控制器/操作没有特定[Authorize]属性时,才会应用全局过滤器.


您还可以通过在生成要应用于每个控制器和操作的过滤器的过程中注入自己来避免使用全局过滤器.您可以添加自己的IApplicationModelProvider或自己的IApplicationModelConvention.两者都允许您添加/删除特定的控制器和操作过滤器.

例如,您可以定义默认授权策略和其他特定策略:

services.AddAuthorization(opts =>
{
    opts.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().RequireRole("admin").Build();
    opts.AddPolicy("Users", policy => policy.RequireAuthenticatedUser().RequireRole("admin", "users"));
});
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建一个新的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>());
Run Code Online (Sandbox Code Playgroud)

有了这个,默认策略将用于这两个控制器:

public class FooController : Controller

[Authorize]
public class BarController : Controller
Run Code Online (Sandbox Code Playgroud)

此处将使用特定的用户策略:

[Authorize(Policy = "Users")]
public class UsersController : Controller
Run Code Online (Sandbox Code Playgroud)

请注意,您仍需要将admin角色添加到每个策略,但至少所有策略都将在单个启动方法中声明.您可以创建自己的方法来构建始终添加管理角色的策略.