Przekierowanie z atrybutu filtru akcji


139

Jaki jest najlepszy sposób na przekierowanie w pliku ActionFilterAttribute. Mam ActionFilterAttributewezwanie IsAuthenticatedAttributeFilteri sprawdziłem wartość zmiennej sesji. Jeśli zmienna ma wartość false, chcę, aby aplikacja przekierowała do strony logowania. Wolałbym przekierować przy użyciu nazwy trasy, SystemLoginjednak w tym momencie każda metoda przekierowania byłaby w porządku.


Odpowiedzi:


187

Ustaw filterContext.Result

Z nazwą trasy:

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

Możesz też zrobić coś takiego:

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

Jeśli chcesz użyć RedirectToAction:

Możesz utworzyć publiczną RedirectToActionmetodę na swoim kontrolerze ( najlepiej na swoim kontrolerze podstawowym ), która po prostu wywoła chroniony RedirectToActionprzed System.Web.Mvc.Controller. Dodanie tej metody pozwala na publiczne wywołanie Twojego RedirectToAction z filtra.

public new RedirectToRouteResult RedirectToAction(string action, string controller)
{
    return base.RedirectToAction(action, controller);
}

Wtedy twój filtr wyglądałby mniej więcej tak:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var controller = (SomeControllerBase) filterContext.Controller;
    filterContext.Result = controller.RedirectToAction("index", "home");
}

8
To działa, ale czy nie powinna być dostępna metoda RedirectToAction?
— Ben Mills,

@BenMills jest jednak po to, protectedabyś nie miał do niego dostępu z poziomu filtra.
— James,

10
Moje pytanie brzmi teraz, dlaczego Microsoft zdecydował, że ten filtr protectedmusi być jakieś rozsądne wyjaśnienie? Czuję się bardzo nieprzyjemnie definiując tę ​​dostępność RedirectToActionbez zrozumienia, dlaczego została ona zamknięta w pierwszej kolejności.
— Matthew Marlin

2
@MatthewMarlin - Zobacz odpowiedź Syakura, aby uzyskać właściwą odpowiedź na przekierowanie do działania. Masz rację, że nie powinieneś wywoływać kontrolera bezpośrednio z filtru akcji - to jest definicja ścisłego sprzężenia.
— NightOwl888

1
@Akbari Czy próbowałeś ustawić właściwość Order atrybutu? Również FilterScope wpłynie na kolejność wykonania.
— CRice

79

Alternatywnie do przekierowania, jeśli wywołuje Twój własny kod, możesz użyć tego:

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

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

Nie jest to zwykłe przekierowanie, ale daje podobny wynik bez zbędnych kosztów ogólnych.


Pomogłeś mi. Dzięki!
— Edgar Salazar

25
Zauważ, że nie powinieneś wywoływać actionContext.Result.ExecuteResultz poziomu swojego filtra akcji - MVC zrobi to automatycznie po uruchomieniu filtru akcji (pod warunkiem, że actionContext.Resultnie jest null).
— NightOwl888

12

Używam MVC4, zastosowałem następujące podejście do przekierowania niestandardowego ekranu html po naruszeniu autoryzacji.

Rozszerz AuthorizeAttributepowiedz CutomAuthorizer zastąpienie OnAuthorizationiHandleUnauthorizedRequest

Zarejestruj CustomAuthorizerw RegisterGlobalFilters.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{

    filters.Add(new CustomAuthorizer());
}

po zidentyfikowaniu unAuthorizedwywołania dostępu HandleUnauthorizedRequesti przekierowaniu do odpowiedniej akcji kontrolera, jak pokazano poniżej.


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

Wygląda na to, że chcesz ponownie zaimplementować lub rozszerzyć AuthorizeAttribute. Jeśli tak, upewnij się, że dziedziczisz to, a nie ActionFilterAttribute, aby umożliwić ASP.NET MVC wykonanie większej ilości pracy za Ciebie.

Ponadto chcesz się upewnić, że autoryzujesz się przed wykonaniem jakiejkolwiek rzeczywistej pracy w metodzie akcji - w przeciwnym razie jedyną różnicą między zalogowanym a niezalogowanym będzie to, jaką stronę zobaczysz po zakończeniu pracy.

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

Jest dobre pytanie z odpowiedzią zawierającą więcej szczegółów na SO.


5

Wypróbuj następujący fragment, powinien być całkiem jasny:

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

To zadziałało dla mnie, musiałem sprawdzić wartości ciągu zapytania, jeśli jakikolwiek użytkownik próbuje zmienić wartości ciągu zapytania i próbuje uzyskać dostęp do danych, które nie są dla niego / niej autoryzowane, a ja przekierowuję je do nieautoryzowanej strony wiadomości, używając ActionFilterAttribute.
— Sameer

3

Oto rozwiązanie, które bierze również pod uwagę, jeśli używasz żądań 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

To działa dla mnie (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

możesz odziedziczyć kontroler, a następnie użyć go w filtrze akcji

wewnątrz klasy ActionFilterAttribute:

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

wewnątrz kontrolera podstawowego:

public class MyController : Controller 
{
    public void  RedirectToAction(string actionName) { 
        base.RedirectToAction(actionName); 
    }
}

Cons. ma to na celu zmianę wszystkich kontrolerów na dziedziczenie z klasy „MyController”

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.