Перенаправление из атрибута фильтра действий

Каков наилучший способ сделать перенаправление в ActionFilterAttribute, у меня есть ActionFilterAttribute называется IsAuthenticatedAttributeFilter и это проверило значение переменной сеанса. Если переменная имеет значение false, я хочу, чтобы приложение перенаправляло на страницу входа. Я бы предпочел перенаправить, используя имя маршрута SystemLogin однако любой метод перенаправления на этом этапе будет в порядке.

8 ответов

Решение

Установить filterContext.Result

С названием маршрута:

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

Вы также можете сделать что-то вроде:

filterContext.Result = new ViewResult
{
    ViewName = SharedViews.SessionLost,
    ViewData = filterContext.Controller.ViewData
};

Если вы хотите использовать RedirectToAction:

Вы могли бы сделать публичным RedirectToAction метод на вашем контроллере (предпочтительно на его базовом контроллере), который просто вызывает защищенный RedirectToAction от System.Web.Mvc.Controller, Добавление этого метода позволяет публичный звонок на ваш 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");
}

В качестве альтернативы перенаправлению, если он вызывает ваш собственный код, вы можете использовать это:

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

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

Это не просто перенаправление, но дает аналогичный результат без лишних затрат.

Я использую MVC4, я использовал следующий подход, чтобы перенаправить пользовательский экран HTML при нарушении авторизации.

простираться AuthorizeAttribute сказать CutomAuthorizerпереопределить OnAuthorization а также HandleUnauthorizedRequest

Зарегистрировать CustomAuthorizer в RegisterGlobalFilters,

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" }

                                         });

    }
}

Похоже, вы хотите повторно реализовать или, возможно, расширить, 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);
    }
}

Есть хороший вопрос с ответом с более подробной информацией здесь о SO.

Попробуйте следующий фрагмент, это должно быть довольно ясно:

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

Это работает для меня (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();
}

Вот решение, которое также учитывает, используете ли вы 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);
        }
    }
}

Вы можете унаследовать свой контроллер, а затем использовать его в вашем фильтре действий

внутри вашего класса 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); 
    }
}

Cons. это изменить все контроллеры для наследования от класса "MyController"

Другие вопросы по тегам