我们如何在ASP.NET MVC中为整个区域设置授权?

Abd*_*med 53 asp.net authorization asp.net-mvc-areas asp.net-mvc-2

我有一个管理区域,我只想要管理员进入该区域.我考虑过将Adminized属性添加到Admin区域中的每个控制器.是不是有优雅的解决方案,还是框架本身没有这个功能?

编辑:对不起,我之前应该提到这个.我正在使用从AuthorizeAttribute派生的自定义AuthorizedAttribute.

Lev*_*evi 53

基于Web.config的安全性几乎应该在MVC应用程序中使用.原因是多个URL可能会触及控制器,并且将这些检查放在Web.config中总是会遗漏某些内容.记住 - 控制器与区域无关,路径与区域相关联.如果没有冲突,MVC控制器工厂将很乐意为Regions /文件夹中的控制器提供非区域请求.

例如,使用默认项目结构,添加带有AdminDefaultController的管理区域,您可以通过/ Admin/AdminDefault/Index /AdminDefault/Index 命中此控制器.

唯一支持的解决方案是将您的属性放在控制器基类上,并确保区域内的每个控制器都是该基类的子类.

  • SURELY更合理的方法是提供一种机制,在给定区域的所有控制器上强制过滤器,而不管您的参数如何.开发人员更可能忘记添加属性.它喜欢系统的人建议他们的用户单独保护文件夹中的每个文件,因为Windows会阻止sys人员在文件夹级别执行此操作.另一个半生不熟的想法IMO.为了善良而保持干爽! (6认同)
  • 无法确保只能通过单个 URL 访问控制器。路由只是用于访问控制器的 *a* 机制;它们不是*该*机制。这就是为什么任何安全属性都需要直接应用于控制器本身,而不是路由(以及扩展到区域)的原因。例如,考虑在 MVC 3 中引入 MvcHandler.ashx。这将通过绕过路由的 *all* 直接调用到 MVC 框架。 (2认同)

Qua*_*ngo 45

我刚刚调查过同样的问题.由于无法根据区域保护控制器,因此可以考虑使用更简单的选项.

为覆盖Controller的每个区域创建基本控制器定义,并为此添加安全性要求.然后你必须确保区域中的每个控制器都覆盖AreaController而不是Controller.例如:

/// <summary>
/// Base controller for all Admin area
/// </summary>
[Authorize(Roles = "Admin")]
public abstract class AdminController : Controller { }
Run Code Online (Sandbox Code Playgroud)

它仍然需要您从此基础派生管理区域中的每个控制器,

public class HomeController : AdminController
{
    // .. actions
}
Run Code Online (Sandbox Code Playgroud)

但至少你有一个点,你可以定义该区域的安全性.

  • 简单的答案是DRY - http://en.wikipedia.org/wiki/Don't_repeat_yourself - 我可以在一行代码中更改受保护的角色,而不是寻找每个[Authorize]属性 (4认同)
  • @AbhimanyuKumarVatsa开发人员忘记从基本控制器继承是与开发人员忘记向控制器添加`[Authorize]`属性相同的问题.解决方案不是故障. (3认同)
  • 是的,这听起来像个好主意.除了MSDN建议其他问题的类似解决方案.传承很好.我喜欢这个答案. (2认同)

Bri*_*ice 14

我刚刚开始这个......但到目前为止,这对我来说非常有用.

我创建了一个自定义AuthorizeAttribute类,并将其添加到RegisterGlobalFilters函数中.

在CustomAuthorizeAttribute中,我根据它所在的区域检查各种条件.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomAuthorizeAttribute());
        filters.Add(new HandleErrorAttribute());
    }
}

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var routeData = httpContext.Request.RequestContext.RouteData;
        var controller = routeData.GetRequiredString("controller");
        var action = routeData.GetRequiredString("action");
        var area = routeData.DataTokens["area"];
        var user = httpContext.User;
        if (area != null && area.ToString() == "Customer")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
        }
        else if (area != null && area.ToString() == "Admin")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
            if (!user.IsInRole("Admin"))
                return false;
        }
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ohn 13

如果您的所有管理代码都在一个控制器中,则将Authorize添加到整个类.

[Authorize]
public class AdminController : Controller
{
     .......
}
Run Code Online (Sandbox Code Playgroud)

  • 这适用于单个控制器.但是我们如何在整个地区做到这一点? (2认同)

aiw*_*wyn 5

当前接受的答案不是最安全的解决方案,因为它要求开发人员始终记住为任何新的控制器或操作继承新的基类(“黑名单”;允许用户访问所有内容,除非手动限制了操作)。当新开发人员不了解您的习惯时,这会特别引起问题。如果这样做的话,很容易忘记继承适当的控制器类,尤其是在您视而不见项目数周,数月或数年之后。如果开发人员忘记继承,则项目中是否存在安全漏洞并不明显。

解决此问题的一种更安全的方法是拒绝对所有请求的访问,然后用允许访问这些动作的角色来修饰每个动作(“白名单”;除非手动允许,否则禁止所有用户访问)。现在,如果开发人员忘记将正确的授权列入白名单,那么用户将让您知道,这就像查看其他控制器以提醒有关如何给予适当访问的权限一样简单。但是,至少没有主要的安全漏洞。

在App_Start / FilterConfig.cs文件中,修改FilterConfig类:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        ...

        //Deny access to all controllers and actions so that only logged in Administrators can access them by default
        filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" });
    }
Run Code Online (Sandbox Code Playgroud)

除非用户以管理员身份登录,否则所有操作都无法访问。然后,对于您希望其他授权用户有权访问的每个操作,只需使用[OverrideAuthorization]和装饰它[Authorize]

在您的业务逻辑中,这允许您以多种方式使用Authorize属性,而不必担心未授权用户访问任何功能。以下是一些示例。

示例1-仅允许登录的Administrator和Dispatcher用户访问Index()Get和Post方法。

public class MarkupCalculatorController : Controller //Just continue using the default Controller class.
{
    // GET: MarkupCalculator
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index()
    {
        //Business logic here.

        return View(...);
    }

    // POST: DeliveryFeeCalculator
    [HttpPost]
    [ValidateAntiForgeryToken]
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM)
    {
        //Business logic here.

        return View(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

示例2-仅允许经过身份验证的用户访问Home控制器的Index()方法。

public class HomeController : Controller
{
    [OverrideAuthorization]
    [Authorize] //Allow all authorized (logged in) users to use this action
    public ActionResult Index()
    {
        return View();
    }

}
Run Code Online (Sandbox Code Playgroud)

示例3-使用[AllowAnonymous]属性可以允许未经身份验证的用户(即匿名用户)访问方法。这也将自动覆盖全局过滤器,而无需使用该[OverrideAuthorization]属性。

    // GET: /Account/Login
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        ...
    }
Run Code Online (Sandbox Code Playgroud)

示例4-仅允许管理员访问缺少该[Authorize]属性的方法。

public class LocationsController : Controller
{

    // GET: Locations
    public ActionResult Index()
    {
        //Business logic here.
        return View(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

一些注意事项。

[OverrideAuthorization]如果要限制对特定角色的特定操作的访问,则必须使用该属性。否则,[Authorize]即使由于全局过滤器而指定了其他角色(例如Dispatcher等),也将忽略属性属性,并且仅允许使用默认角色(在我的示例中为Administrator)。任何未经授权的用户都将被重定向到登录屏幕。

使用该[OverrideAuthorization]属性会使操作忽略您设置的全局过滤器。因此,每当您使用覆盖时,都必须重新应用该[Authorize]属性,以使操作保持安全。

关于整个区域和控制器

要按区域进行限制(如您所要求的),请在控制器上放置[OverrideAuthorization]and [Authorize]属性,而不是将单个操作放置。