web-dev-qa-db-fra.com

Rediriger depuis l'attribut de filtre d'action

Quelle est la meilleure façon de faire une redirection dans une ActionFilterAttribute. J'ai une ActionFilterAttribute appelée IsAuthenticatedAttributeFilter et qui vérifie la valeur d'une variable de session. Si la variable est false, 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 SystemLogin mais toute méthode de redirection à ce stade serait satisfaisante.

119
ryanzec

Définir filterContext.Result

Avec le nom de la route:

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

Vous pouvez aussi faire quelque chose comme:

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

Si vous voulez utiliser RedirectToAction:

Vous pouvez créer une méthode publique RedirectToAction sur votre contrôleur (de préférence sur son contrôleur de base) qui appelle simplement la valeur protégée RedirectToAction à partir de System.Web.Mvc.Controller. L'ajout de cette méthode permet un appel public à votreRedirectToAction à partir du 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");
}
165
CRice

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 redirection pure mais donne un résultat similaire sans surcharge inutile.

71
Syakur Rahman

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

Étendre AuthorizeAttribute dire CutomAuthorizer Remplacer les OnAuthorization et HandleUnauthorizedRequest

Enregistrez la CustomAuthorizer dans la RegisterGlobalFilters.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{

    filters.Add(new CustomAuthorizer());
}

lors de l'identification de unAuthorized accès, appelez HandleUnauthorizedRequestet redirigez 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" }

                                         });

    }
}
11
user2834076

Il semble que vous souhaitiez ré-implémenter, ou éventuellement étendre, AuthorizeAttribute. Si tel est le cas, vous devez vous assurer que vous héritez de cela, et non de ActionFilterAttribute, afin de permettre à ASP.NET MVC de se charger davantage du travail à votre place.

En outre, vous voulez vous assurer que vous autorisez avant que ne réalisiez aucun travail réel dans la méthode d'action - sinon, la seule différence entre connecté et non connecté 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.

9
Tomas Aschan

Essayez l'extrait 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);
  }
}
4
msoliman

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

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();
}
0
mortenma71

vous pouvez hériter de votre contrôleur puis l'utiliser à l'intérieur de 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");

dans votre contrôleur de base: 

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

Les inconvénients. cela consiste à changer tous les contrôleurs pour hériter de la classe "MyController"

0
msoliman