Reindirizzamento dall'attributo Filtro azione


139

Qual è il modo migliore per eseguire un reindirizzamento in un ActionFilterAttribute. Ho ActionFilterAttributechiamato IsAuthenticatedAttributeFiltere verificato il valore di una variabile di sessione. Se la variabile è falsa, voglio che l'applicazione reindirizzi alla pagina di accesso. Preferirei reindirizzare utilizzando il nome del percorso, SystemLogintuttavia qualsiasi metodo di reindirizzamento a questo punto andrebbe bene.


Risposte:


187

Impostare filterContext.Result

Con il nome del percorso:

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

Puoi anche fare qualcosa del tipo:

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

Se vuoi usare RedirectToAction:

È possibile creare un RedirectToActionmetodo pubblico sul controller ( preferibilmente sul controller di base ) che chiama semplicemente il protetto RedirectToActionda System.Web.Mvc.Controller. L'aggiunta di questo metodo consente una chiamata pubblica al tuo RedirectToAction dal filtro.

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

Quindi il tuo filtro sarebbe simile a:

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

8
Funziona, ma non dovrebbe essere disponibile un metodo RedirectToAction?
Ben Mills,

@BenMills c'è, tuttavia, è protectedcosì non avresti accesso ad esso dal filtro.
James,

10
La mia domanda ora è: perché Microsoft ha deciso di creare questo filtro? protectedCi deve essere una spiegazione ragionevole? Mi sento molto sporca a ridefinire questa accessibilità RedirectToActionsenza capire perché sia ​​stata incapsulata in primo luogo.
Matthew Marlin,

2
@MatthewMarlin - Vedi la risposta di Syakur per la risposta giusta per il reindirizzamento a un'azione. Hai ragione a dire che non dovresti chiamare un controller direttamente da un filtro di azione - questa è la definizione di accoppiamento stretto.
NightOwl888,

1
@Akbari hai provato a impostare la proprietà Order degli attributi? Anche FilterScope influirà sull'ordine di esecuzione.
CRice,

79

In alternativa a un reindirizzamento, se si chiama il proprio codice, è possibile utilizzare questo:

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

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

Non è un reindirizzamento puro ma dà un risultato simile senza spese generali inutili.


Mi hai aiutato. Grazie!
Edgar Salazar,

25
Tieni presente che non dovresti chiamare actionContext.Result.ExecuteResultdal tuo filtro azioni: MVC lo farà automaticamente dopo l'esecuzione del filtro azioni (a condizione che actionContext.Resultnon sia nullo).
NightOwl888,

12

Sto usando MVC4, ho usato il seguente approccio per reindirizzare una schermata HTML personalizzata in caso di violazione dell'autorizzazione.

Estendi AuthorizeAttributedire CutomAuthorizer ignora il OnAuthorizationeHandleUnauthorizedRequest

Registrare il CustomAuthorizerin RegisterGlobalFilters.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{

    filters.Add(new CustomAuthorizer());
}

dopo aver identificato la unAuthorizedchiamata di accesso HandleUnauthorizedRequeste il reindirizzamento all'azione del controller interessata, come mostrato di seguito.


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

Sembra che tu voglia implementare nuovamente, o possibilmente estenderlo AuthorizeAttribute. In tal caso, dovresti assicurarti di ereditare quello e nonActionFilterAttribute , al fine di consentire ad ASP.NET MVC di fare più lavoro per te.

Inoltre, vuoi assicurarti di autorizzare prima di eseguire qualsiasi lavoro reale nel metodo di azione - altrimenti, l'unica differenza tra il login e non sarà la pagina che vedrai al termine del lavoro.

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

C'è una buona domanda con una risposta con maggiori dettagli qui su SO.


5

Prova il seguente frammento, dovrebbe essere abbastanza chiaro:

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

Questo ha funzionato per me, ho dovuto controllare i valori della stringa di query se un utente tenta di modificare i valori della stringa di query e tenta di accedere a dati che non sono autorizzati da lui / come se li sto reindirizzando alla pagina di messaggio non autorizzata, utilizzando ActionFilterAttribute.
Sameer

3

Ecco una soluzione che tiene conto anche se si utilizzano richieste 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

Questo funziona per me (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

potresti ereditare il tuo controller e poi usarlo all'interno del tuo filtro azioni

nella tua classe ActionFilterAttribute:

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

all'interno del controller di base:

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

Cons. di questo è di cambiare tutti i controller per ereditare dalla classe "MyController"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.