将动作过滤器应用于ASP.NET MVC站点的一个部分中的每个控制器?

Nei*_*den 5 asp.net-mvc

我已经看到了一个类似问题的一个很好的答案,它通过继承来自用你自己的ActionFilter属性修饰的新基类的所有控制器来解释如何将一些逻辑应用于你网站的所有请求.

我想根据用户访问的网站区域找到一种方法.

例如,我将有一个带有View操作的Product控制器,但我想允许它用于以下两个URL:

/ Product/View/321 - 将产品ID 321显示为'normal'用户/ Admin/Product/View/321 - 使用相同的View控制器,但为我的管理员用户吐出额外的功能.

我可以将"admin"作为名为"user"的参数传递到我的产品控制器上的视图操作中,以显示管理员的额外信息,此处显示了执行此操作的方法.但我当时需要做的是确认我的用户被允许查看该网址.我不想用检查身份验证的ActionAttribute来装饰我的Product控制器,因为当未经身份验证的用户(和登录的管理员)在/ Product/View/321查看它时,我希望他们都能看到标准视图.

所以我什么喜欢做的,下面是伪代码描述:

当调用格式为"{userlevel}/{controller}/{action}/{id}"的网址时,我想调用另一个执行身份验证检查的控制器,然后"链接"到原始{控制器并传递{action},{id}​​和{userlevel}属性.

我该怎么办?

(我知道对每次调用控制器进行检查的开销可能很小.我想这样做,因为除了用户身份验证检查之外,我以后可能需要做一些更昂贵的事情而且我会我希望只为我网站的低流量管理区域运行该代码.似乎没有必要为网站的每个公共用户执行这些操作)

Alc*_*nja 4

起初我认为这可能就像添加一条新路线一样简单:

routes.MapRoute(
    "Admin",
    "Admin/{*pathInfo}",
    new { controller="Admin", action="Index", pathInfo="" }
    );
Run Code Online (Sandbox Code Playgroud)

然后有一个像这样的控制器:

public class AdminController : Controller
{
    public ActionResult Index(string pathInfo)
    {
        //Do admin checks, etc here....
        return Redirect("/" + pathInfo);
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,遗憾的是,用于执行重定向的所有可用选项(即 Redirect、RedirectToAction 和 RedirectToRoute)都执行 302 样式重定向。基本上,这意味着您/Admin/Product/Whatever将执行然后反弹回浏览器,告诉它重定向到/Product/Whatever一个全新的请求,这意味着您已经丢失了上下文。我不知道保持重定向服务器端的干净方法(即像Server.Transfer旧的那样),显然SO 社区也不知道......

(显然,这是一个非解决方案,因为它不能解决你的问题,但我想我还是把它放在这里,以防你可以以其他方式使用这些想法)


那么,真正解决问题的方法是什么呢?另一个想法是使用 ActionFilter (是的,我知道你说过你不想这样做,但我认为以下内容将满足你的目的)。添加一条新路线,如下所示:

routes.MapRoute(
    "Admin",
    "Admin/{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "", userLevel = "Admin" }
    );
Run Code Online (Sandbox Code Playgroud)

然后添加一个像这样的 ActionFilter (您可以通过您提到的基本控制器对象将其应用于所有请求):

public class ExtendedAdminViewAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        object userLevel = filterContext.RouteData.Values["userLevel"];
        if (userLevel != null && userLevel.ToString() == "Admin")
        {
            //Do your security auth checks to ensure they really are an admin
            //Then do your extra admin logic...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,尽管它使用适用于所有请求的 ActionFilter,但在大多数正常情况下(即 的请求/Product/Whatever)完成的唯一额外工作是对该路由数据位 ( userLevel) 进行单次检查。换句话说,您确实应该看到普通用户的性能受到影响,因为您只需执行完整的身份验证检查和额外的管理工作(如果他们通过/Admin/Product/Whatever.