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

标签 c# asp.net-core asp.net-core-mvc asp.net-core-1.0

我正在尝试在 ASP.NET Core 1.0 (MVC 6) 网络应用程序中设置授权。

限制性更强的方法 - 默认情况下,我想将所有 Controller 和操作方法限制为具有 Admin 角色的用户。因此,我添加了一个全局授权属性,例如:

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

然后我想允许具有特定角色的用户访问具体的 Controller 。例如:

[Authorize(Roles="Admin,UserManager")]
public class UserControler : Controller{}

这当然行不通,因为“全局过滤器”不允许 UserManager 访问 Controller ,因为他们不是“管理员”。

在 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);
    }
}

我尝试创建自定义 AuthorizeFilter,但没有成功。 API似乎有所不同。

所以我的问题是:是否可以设置默认策略,然后针对特定的 Controller 和操作覆盖它。或者类似的东西。 我不想接受这个

[Authorize(Roles="Admin,[OtherRoles]")]

在每个 Controller / Action 上,因为这是一个潜在的安全问题。如果我不小心忘记设置 Admin 角色会怎样。

最佳答案

您需要稍微尝试一下该框架,因为您的全局策略比您想要应用于特定 Controller 和操作的策略更具限制性:

  • 默认只有管理员用户可以访问您的应用
  • 特定角色也将被授予访问某些 Controller 的权限(例如 UserManagers 访问 UsersController)

正如您已经注意到的,拥有全局过滤器意味着只有 Admin 用户才能访问 Controller 。当您在 UsersController 上添加附加属性时,只有都是 Admin UserManager< 的用户/em> 将有访问权限。

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

  • 在 MVC 6 中 [Authorize]属性不包含授权逻辑。
  • 而不是 AuthorizeFilter是具有调用授权服务以确保满足策略的 OnAuthorizeAsync 方法的方法。
  • 具体 IApplicationModelProvider用于为每个具有 [Authorize] 属性的 Controller 和操作添加 AuthorizeFilter

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

仅当 Controller /操作没有特定的 [Authorize] 属性时,这才会应用您的全局过滤器。


您还可以通过将自己注入(inject)到生成要应用于每个 Controller 和操作的过滤器的过程中来避免使用全局过滤器。您可以添加自己的 IApplicationModelProvider 或您自己的 IApplicationModelConvention。两者都可以让您添加/删除特定的 Controller 和操作过滤器。

例如,您可以定义默认授权策略和额外的特定策略:

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

然后您可以创建一个新的 IApplicatioModelProvider,它将默认策略添加到每个没有自己的 [Authorize] 属性的 Controller (应用程序约定是非常相似,可能更符合框架的扩展方式。我只是快速使用现有的 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>());

有了这个,默认策略将在这两个 Controller 上使用:

public class FooController : Controller

[Authorize]
public class BarController : Controller

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

[Authorize(Policy = "Users")]
public class UsersController : Controller

请注意,您仍然需要为每个策略添加管理员角色,但至少您的所有策略都将在一个启动方法中声明。您可能会创建自己的方法来构建将始终添加管理员角色的策略。

关于c# - 覆盖 ASP.NET Core 1.0 MVC 中的全局授权过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35825021/

相关文章:

c# - 这些可等待的方法有什么区别?

c# - 如何将 sql union 与连接查询一起使用

asp.net - 如何在构建期间设置 appsettings.json 文件中的键值

c# - aspnet 5 RESTful api ModelState.IsValid == true 即使值根据 DataAnnotations 无效

c# - asp.net mvc 6 模型绑定(bind)到复杂集合 - IList<T>

c# - 从类访问 Properties.Settings.Default?

c# - 获取相对路径的绝对路径

c# - Asp.NET Core 自定义 Input Tag Helper 呈现重复的复选框

c# - 从 Razor 类库内部访问 Microsoft.AspNetCore.Components.Server.Circuits

c# - 使用 asp.net core 2.2 创建类别和子类别依赖列表框