Rediriger à partir de l'attribut de filtre d'action

139

Quelle est la meilleure façon de faire une redirection dans un fichier ActionFilterAttribute. J'ai un ActionFilterAttributeappelé IsAuthenticatedAttributeFilteret qui a vérifié la valeur d'une variable de session. Si la variable est fausse, je souhaite que l'application soit redirigée vers la page de connexion. Je préférerais rediriger en utilisant le nom de la route, SystemLoginmais toute méthode de redirection à ce stade conviendrait.

Ryanzec
la source

Réponses:

187

Définir filterContext.Result

Avec le nom de l'itinéraire:

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

Vous pouvez également faire quelque chose comme:

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

Si vous souhaitez utiliser RedirectToAction:

Vous pouvez créer une RedirectToActionméthode publique sur votre contrôleur (de préférence sur son contrôleur de base ) qui appelle simplement le protected RedirectToActionfrom System.Web.Mvc.Controller. L'ajout de cette méthode permet un appel public à votre RedirectToAction depuis le filtre.

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

Ensuite, votre filtre ressemblerait à quelque chose comme:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var controller = (SomeControllerBase) filterContext.Controller;
    filterContext.Result = controller.RedirectToAction("index", "home");
}
CRice
la source
8
Cela fonctionne, mais ne devrait-il pas y avoir une méthode RedirectToAction disponible?
Ben Mills
@BenMills il y a, cependant, c'est pour protectedque vous n'y ayez pas accès à partir du filtre.
James
10
Ma question maintenant est pourquoi Microsoft a-t-il décidé de créer ce filtre, protectedil doit y avoir une explication raisonnable? Je me sens très sale de redéfinir cette accessibilité RedirectToActionsans comprendre pourquoi elle a été encapsulée en premier lieu.
Matthew Marlin
2
@MatthewMarlin - Voir la réponse de Syakur pour la bonne réponse pour rediriger vers une action. Vous avez raison de ne pas appeler un contrôleur directement à partir d'un filtre d'action - c'est la définition du couplage étroit.
NightOwl888
1
@Akbari avez-vous essayé de définir la propriété Order des attributs? FilterScope aura également un impact sur l'ordre d'exécution.
CRice
79

Alternativement à une redirection, si elle appelle votre propre code, vous pouvez utiliser ceci:

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

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

Ce n'est pas une pure redirection mais donne un résultat similaire sans surcharge inutile.

Syakur Rahman
la source
Vous m'avez aidé. Merci!
Edgar Salazar
25
Notez que vous ne devriez pas appeler à actionContext.Result.ExecuteResultpartir de votre filtre d'action - MVC le fera automatiquement après l'exécution du filtre d'action (fourni actionContext.Resultn'est pas nul).
NightOwl888
12

J'utilise MVC4, j'ai utilisé l'approche suivante pour rediriger un écran HTML personnalisé en cas de violation d'autorisation.

Prolonger AuthorizeAttributedire CutomAuthorizer remplacer leOnAuthorization etHandleUnauthorizedRequest

Enregistrez le CustomAuthorizerdans le RegisterGlobalFilters.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{

    filters.Add(new CustomAuthorizer());
}

lors de l'identification de l' unAuthorizedappel d'accès HandleUnauthorizedRequestet rediriger vers l'action du contrôleur concerné comme indiqué ci-dessous.


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

                                         });

    }
}
user2834076
la source
9

On dirait que vous voulez ré-implémenter, ou peut - être prolonger, AuthorizeAttribute. Si tel est le cas, vous devez vous assurer que vous héritez de cela, et non ActionFilterAttribute, afin de laisser ASP.NET MVC faire plus de travail pour vous.

En outre, vous voulez vous assurer que vous autorisez avant de faire tout le travail réel dans la méthode d'action - sinon, la seule différence entre connecté et non sera la page que vous voyez lorsque le travail est terminé.

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

Il y a une bonne question avec une réponse avec plus de détails ici sur SO.

Tomas Aschan
la source
5

Essayez l'extrait de code suivant, cela devrait être assez clair:

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);
  }
}
Muhammad Soliman
la source
Cela a fonctionné pour moi, j'ai dû vérifier les valeurs de la chaîne de requête si un utilisateur tente de modifier les valeurs de la chaîne de requête et tente d'accéder à des données qui ne lui sont pas autorisées que je les redirige vers une page de message non autorisée, en utilisant ActionFilterAttribute.
Sameer
3

Voici une solution qui prend également en compte si vous utilisez des requêtes 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);
        }
    }
}
Mike
la source
1

Cela fonctionne pour moi (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();
}
mortenma71
la source
0

vous pouvez hériter de votre contrôleur puis l'utiliser dans votre filtre d'action

dans votre classe ActionFilterAttribute:

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

à l'intérieur de votre contrôleur de base:

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

Les inconvénients. de ceci est de changer tous les contrôleurs pour hériter de la classe "MyController"

Muhammad Soliman
la source