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

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

【问题讨论】:

标签: c# asp.net-mvc asp.net-mvc-3 redirect routes


【解决方案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”类继承

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-11-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多