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


139

Який найкращий спосіб зробити переадресацію в ActionFilterAttribute. У мене є ActionFilterAttributeвиклик, IsAuthenticatedAttributeFilterякий перевіряв значення змінної сесії. Якщо змінна хибна, я хочу, щоб програма переспрямовувалась на сторінку входу. Я вважаю за краще переадресувати за допомогою назви маршруту, SystemLoginоднак будь-який метод переадресації в цій точці буде добре.


Відповіді:


187

Встановити 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");
}

8
Це працює, але чи не повинен бути доступний метод RedirectToAction?
Бен Міллз

@BenMills, однак, це protectedтак, що ви не мали б до нього доступу з фільтра.
Джеймс

10
Зараз у мене запитання: чому Microsoft вирішила зробити цей фільтр protected, має бути певне пояснення? Я дуже брудно переосмислюю цю доступність, RedirectToActionне розуміючи, чому вона в першу чергу була інкапсульована.
Метью Марлін

2
@MatthewMarlin - Правильну відповідь на переадресацію до дії див. Ви правильні, що не слід викликати контролер безпосередньо з фільтра дій - це визначення щільної зв'язку.
NightOwl888

1
@Akbari Ви спробували встановити властивість Order для атрибутів? Також FilterScope буде виконувати порядок виконання впливу.
CRice

79

Як варіант переспрямування, якщо він викликає власний код, ви можете скористатися цим:

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

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

Це не є чистим переспрямуванням, але дає подібний результат без зайвих накладних витрат.


Ви МОЄТЕ допомогти мені. Дякую!
Едгар Салазар

25
Зауважте, що вам не слід дзвонити actionContext.Result.ExecuteResultз фільтра дій - MVC зробить це автоматично після запуску фільтра дій (за умови, що actionContext.Resultце недійсне).
NightOwl888

12

Я використовую 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" }

                                         });

    }
}

9

Схоже , що ви хочете повторно реалізувати, або , можливо , продовжити, 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);
    }
}

Тут є хороший запитання з відповіддю з більш детальною інформацією тут, на ЗО.


5

Спробуйте наступний фрагмент, він повинен бути досить зрозумілим:

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.
Самєр

3

Ось рішення, яке також враховується, якщо ви використовуєте запити 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);
        }
    }
}

1

Це працює для мене (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();
}

0

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

всередині вашого класу 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"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.