覆盖ASP.NET Core 1.0 MVC中的全局授权过滤器 [英] Override global authorize filter in ASP.NET Core 1.0 MVC

查看:63
本文介绍了覆盖ASP.NET Core 1.0 MVC中的全局授权过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to set up authorization in ASP.NET Core 1.0 (MVC 6) web app.

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

More restrictive approach - by default I want to restrict all controllers and action methods to users with Admin role. So, I am adding a global authorize attribute like:

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

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

Then I want to allow users with specific roles to access concrete controllers. For example:

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

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

Which of course will not work, as the "global filter" will not allow the UserManager to access the controller as they are not "admins".

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

In MVC5, I was able to implement this by creating a custom authorize attribute and putting my logic there. Then using this custom attribute as a global. For example:

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似乎有所不同.

I tried to create a custom AuthorizeFilter, but no success. API seems to be different.

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

So my question is: Is it possible to set up default policy and then override it for specific controllers and actions. Or something similar. I don't want to go with this

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

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

on every controller/action, as this is a potential security problem. What will happen if I accidentally forget to put the Admin role.

推荐答案

由于您的全局策略比您要应用于特定控制器和操作的全局策略更具限制性,因此您将需要使用该框架:

You will need to play with the framework a bit since your global policy is more restrictive than the one you want to apply to specific controllers and actions:

  • 默认情况下,只有 Admin 用户可以访问您的应用程序
  • 还将授予特定角色某些控制器的访问权限(例如 UserManagers 访问UsersController)
  • By default only Admin users can access your application
  • Specific roles will also be granted access to some controllers (like UserManagers accessing the UsersController)

您已经知道,拥有全局过滤器意味着只有 Admin 用户可以访问控制器.当您在UsersController上添加其他属性时,只有同时 Admin UserManager 的用户访问.

As you have already noticied, having a global filter means that only Admin users will have access to a controller. When you add the additional attribute on the UsersController, only users that are both Admin and UserManager will have access.

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

It is possible to use a similar approach to the MVC 5 one, but it works in a different way.

  • 在MVC 6中, [Authorize] 属性不包含授权逻辑.
  • 代替 是具有OnAuthorizeAsync方法的一种,该方法调用授权服务以确保策略得到满足.
  • 特定的 用于为每个具有[Authorize]属性的控制器和动作添加AuthorizeFilter.
  • In MVC 6 the [Authorize] attribute does not contain the authorization logic.
  • Instead the AuthorizeFilter is the one that has an OnAuthorizeAsync method calling the authorization service to make sure policies are satisfied.
  • A specific IApplicationModelProvider is used to add an AuthorizeFilter for every controller and action that has an [Authorize] attribute.

一个选项可能是重新创建IsAdminOrAuthorizeAttribute,但是这次是作为AuthorizeFilter,然后您将其添加为全局过滤器:

One option could be to recreate your IsAdminOrAuthorizeAttribute, but this time as an AuthorizeFilter that you will then add as a global filter:

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]属性时,才应用全局过滤器.

This would apply your global filter only when the controller/action doesn't have a specific [Authorize] attribute.

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

You could also avoid having a global filter by injecting yourself in the process that generates the filters to be applied for every controller and action. You can either add your own IApplicationModelProvider or your own IApplicationModelConvention. Both will let you add/remove specific controller and actions filters.

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

For example, you can define a default authorization policy and extra specific policies:

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

然后,您可以创建一个新的IApplicatioModelProvider,它将为没有自己的[Authorize]属性的每个控制器添加默认策略(应用程序约定非常相似,并且可能与框架的使用方式更加一致)打算进行扩展.我只是很快地将现有的AuthorizationApplicationModelProvider用作指南):

Then you can create a new IApplicatioModelProvider that will add the default policy to every controller that doesn't have its own [Authorize] attribute (An application convention would be very similar and probably more aligned with the way the framework is intended to be extended. I just quickly used the existing AuthorizationApplicationModelProvider as a guide):

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>());

在此位置上,将在这两个控制器上使用默认策略:

With this in place, the default policy will be used on these 2 controllers:

public class FooController : Controller

[Authorize]
public class BarController : Controller

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

And the specific Users policy will be used here:

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

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

Notice that you still need to add the admin role to every policy, but at least all your policies will be declared in a single startup method. You could probably create your own methods for building policies that will always add the admin role.

这篇关于覆盖ASP.NET Core 1.0 MVC中的全局授权过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆