从动作过滤器属性重定向

Posted

技术标签:

【中文标题】从动作过滤器属性重定向【英文标题】:Redirect From Action Filter Attribute 【发布时间】:2011-07-24 03:00:32 【问题描述】:

ActionFilterAttribute 中进行重定向的最佳方式是什么?我有一个名为IsAuthenticatedAttributeFilterActionFilterAttribute,它检查了会话变量的值。如果变量为 false,我希望应用程序重定向到登录页面。我更喜欢使用路由名称SystemLogin 进行重定向,但是此时任何重定向方法都可以。

【问题讨论】:

Check this answer. Hope this will help you. 【参考方案1】:

设置 filterContext.Result

带有路线名称:

filterContext.Result = new RedirectToRouteResult("SystemLogin", routeValues);

你也可以这样做:

filterContext.Result = new ViewResult

    ViewName = SharedViews.SessionLost,
    ViewData = filterContext.Controller.ViewData
;

如果你想使用RedirectToAction:

您可以在您的控制器(最好在其基本控制器)上创建一个公开的RedirectToAction 方法,该方法只需从System.Web.Mvc.Controller 调用受保护的RedirectToAction。添加此方法允许从过滤器公开调用 your RedirectToAction

public new RedirectToRouteResult RedirectToAction(string action, string controller)

    return base.RedirectToAction(action, controller);

那么您的过滤器将如下所示:

public override void OnActionExecuting(ActionExecutingContext filterContext)

    var controller = (SomeControllerBase) filterContext.Controller;
    filterContext.Result = controller.RedirectToAction("index", "home");

【讨论】:

这可行,但不应该有可用的 RedirectToAction 方法吗? @BenMills,但是,它是 protected,因此您无法通过过滤器访问它。 我现在的问题是为什么微软决定做这个过滤器protected一定有一些合理的解释?重新定义 RedirectToAction 的可访问性,我觉得很肮脏,不明白为什么首先要封装它。 @MatthewMarlin - 请参阅 Syakur 的答案以获得重定向到操作的正确答案。你是正确的,你不应该直接从动作过滤器调用控制器——这就是紧耦合的定义。 @Akbari 您是否尝试过设置属性的 Order 属性? FilterScope 也会影响执行顺序。【参考方案2】:

或者重定向,如果它调用你自己的代码,你可以使用这个:

actionContext.Result = new RedirectToRouteResult(
    new RouteValueDictionary(new  controller = "Home", action = "Error" )
);

actionContext.Result.ExecuteResult(actionContext.Controller.ControllerContext);

这不是纯粹的重定向,但会产生类似的结果而没有不必要的开销。

【讨论】:

你确实帮助了我。谢谢! 请注意,您不应在操作过滤器中调用 actionContext.Result.ExecuteResult - MVC 将在操作过滤器运行后自动执行此操作(前提是 actionContext.Result 不为空)。【参考方案3】:

我正在使用 MVC4,我使用以下方法在违反授权时重定向自定义 html 屏幕。

扩展AuthorizeAttributeCutomAuthorizer 覆盖OnAuthorizationHandleUnauthorizedRequest

RegisterGlobalFilters 中注册CustomAuthorizer

public static void RegisterGlobalFilters(GlobalFilterCollection filters)


    filters.Add(new CustomAuthorizer());

识别unAuthorized访问调用HandleUnauthorizedRequest并重定向到相关的控制器操作,如下所示。


public class CustomAuthorizer : AuthorizeAttribute


    public override void OnAuthorization(AuthorizationContext filterContext)
    
        bool isAuthorized = IsAuthorized(filterContext); // check authorization
        base.OnAuthorization(filterContext);
        if (!isAuthorized && !filterContext.ActionDescriptor.ActionName.Equals("Unauthorized", StringComparison.InvariantCultureIgnoreCase)
            && !filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.Equals("LogOn", StringComparison.InvariantCultureIgnoreCase))
        

            HandleUnauthorizedRequest(filterContext);

        
    

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    
        filterContext.Result =
       new RedirectToRouteResult(
           new RouteValueDictionary "controller", "LogOn" ,
                                           "action", "Unauthorized" 

                                         );

    

【讨论】:

【参考方案4】:

听起来您想重新实现或可能扩展AuthorizeAttribute。如果是这样,您应该确保继承它,而不是 ActionFilterAttribute,以便让 ASP.NET MVC 为您完成更多工作。

此外,您要确保在操作方法中执行任何实际工作之前授权 - 否则,登录和未登录之间的唯一区别将是您何时看到的页面工作完成了。

public class CustomAuthorizeAttribute : AuthorizeAttribute

    public override void OnAuthorization(AuthorizationContext filterContext)
    
        // Do whatever checking you need here

        // If you want the base check as well (against users/roles) call
        base.OnAuthorization(filterContext);
    

有一个很好的question 和一个answer,这里有更多关于 SO 的详细信息。

【讨论】:

【参考方案5】:

试试下面的sn-p,应该很清楚了:

public class AuthorizeActionFilterAttribute : ActionFilterAttribute

  public override void OnActionExecuting(FilterExecutingContext filterContext)
  
    HttpSessionStateBase session = filterContext.HttpContext.Session;
    Controller controller = filterContext.Controller as Controller;

    if (controller != null)
    
      if (session["Login"] == null)
      
        filterContext.Cancel = true;
        controller.HttpContext.Response.Redirect("./Login");
      
    

    base.OnActionExecuting(filterContext);
  

【讨论】:

这对我有用,如果任何用户尝试更改查询字符串值并尝试访问未经授权的数据,我必须检查查询字符串值,而不是将它们重定向到未经授权的消息页面,使用 ActionFilterAttribute。【参考方案6】:

如果您使用 Ajax 请求,这里也有一个解决方案。

using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace YourNamespace        
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeCustom : ActionFilterAttribute 
        public override void OnActionExecuting(ActionExecutingContext context) 
            if (YourAuthorizationCheckGoesHere)                
                string area = "";// leave empty if not using area's
                string controller = "ControllerName";
                string action = "ActionName";
                var urlHelper = new UrlHelper(context.RequestContext);                  
                if (context.HttpContext.Request.IsAjaxRequest()) // Check if Ajax
                    if(area == string.Empty)
                        context.HttpContext.Response.Write($"<script>window.location.reload('urlHelper.Content(System.IO.Path.Combine(controller, action))');</script>");
                    else
                        context.HttpContext.Response.Write($"<script>window.location.reload('urlHelper.Content(System.IO.Path.Combine(area, controller, action))');</script>");
                 else   // Non Ajax Request                      
                    context.Result = new RedirectToRouteResult(new RouteValueDictionary( new area, controller, action ));             
            
            base.OnActionExecuting(context);
        
    

【讨论】:

【参考方案7】:

这对我有用(asp.net core 2.1)

using JustRide.Web.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyProject.Web.Filters

    public class IsAuthenticatedAttribute : ActionFilterAttribute
    
        public override void OnActionExecuting(ActionExecutingContext context)
        
            if (context.HttpContext.User.Identity.IsAuthenticated)
                context.Result = new RedirectToActionResult(nameof(AccountController.Index), "Account", null);
        
    




[AllowAnonymous, IsAuthenticated]
public IActionResult Index()

    return View();

【讨论】:

【参考方案8】:

你可以继承你的控制器,然后在你的动作过滤器中使用它

在 ActionFilterAttribute 类中:

   if( filterContext.Controller is MyController )
      if(filterContext.HttpContext.Session["login"] == null)
           (filterContext.Controller as MyController).RedirectToAction("Login");

在你的基本控制器内部:

public class MyController : Controller 

    public void  RedirectToAction(string actionName)  
        base.RedirectToAction(actionName); 
    

缺点。这就是将所有控制器更改为从“MyController”类继承

【讨论】:

以上是关于从动作过滤器属性重定向的主要内容,如果未能解决你的问题,请参考以下文章

从一个区域的动作重定向到“根”区域中的动作?

从 global.asax 中的 Application_BeginRequest 重定向到一个动作

从一个控制器动作发布到另一个控制器动作(不重定向)

Play framework 1.x 重定向删除动作

Tuckey 过滤器 - https 重定向

在 Play 框架中重定向到同一控制器中的动作