Redirecionar do atributo do filtro de ação


139

Qual é a melhor maneira de fazer um redirecionamento em um ActionFilterAttribute. Eu tenho um ActionFilterAttributechamado IsAuthenticatedAttributeFiltere que verificou o valor de uma variável de sessão. Se a variável for falsa, desejo que o aplicativo seja redirecionado para a página de login. Eu preferiria redirecionar usando o nome da rota, SystemLoginno entanto, qualquer método de redirecionamento neste momento seria bom.


Respostas:


186

Definir filterContext.Result

Com o nome da rota:

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

Você também pode fazer algo como:

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

Se você deseja usar RedirectToAction:

Você pode criar um RedirectToActionmétodo público no seu controlador (de preferência no controlador base ) que simplesmente chama o protegido RedirectToActionde System.Web.Mvc.Controller. A adição deste método permite uma chamada pública para você a RedirectToAction partir do filtro.

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

Em seguida, seu filtro seria algo como:

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

8
Isso funciona, mas não deveria haver um método RedirectToAction disponível?
Ben Mills

@BenMills, no entanto, é protectedpara que você não tenha acesso a ele a partir do filtro.
James

10
Minha pergunta agora é por que a Microsoft decidiu fazer esse filtro. protectedDeve haver alguma explicação razoável? Eu me sinto muito sujo redefinindo essa acessibilidade RedirectToActionsem entender por que ela foi encapsulada em primeiro lugar.
Marlin Matthew

2
@MatthewMarlin - Veja a resposta de Syakur para a resposta certa para redirecionar para uma ação. Você está certo de que não deve chamar um controlador diretamente de um filtro de ação - essa é a definição de acoplamento rígido.
24416 NightOwl888

1
@ Akbari, você tentou definir a propriedade Order dos atributos? O FilterScope também afetará a ordem de execução.
CRice 3/17/17

79

Como alternativa a um redirecionamento, se estiver chamando seu próprio código, você pode usar o seguinte:

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

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

Não é um redirecionamento puro, mas fornece um resultado semelhante sem sobrecarga desnecessária.


Você me ajudou. Obrigado!
Edgar Salazar

25
Observe que você não deve chamar actionContext.Result.ExecuteResultde dentro do seu filtro de ação - o MVC fará isso automaticamente após a execução do filtro de ação (desde que actionContext.Resultnão seja nulo).
24416 NightOwl888

12

Estou usando o MVC4, usei a seguinte abordagem para redirecionar uma tela html personalizada após violação da autorização.

Estender AuthorizeAttributedizer CutomAuthorizer substituir o OnAuthorizationeHandleUnauthorizedRequest

Registre o CustomAuthorizerno RegisterGlobalFilters.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{

    filters.Add(new CustomAuthorizer());
}

ao identificar a unAuthorizedchamada de acesso HandleUnauthorizedRequeste redirecionar para a ação do controlador em questão, como mostrado abaixo.


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

Parece que você deseja reimplementar ou possivelmente estender AuthorizeAttribute. Em caso afirmativo, você deve herdar isso, e não ActionFilterAttribute, para permitir que o ASP.NET MVC faça mais do seu trabalho.

Além disso, você deseja certificar-se de autorizar antes de executar qualquer trabalho real no método de ação - caso contrário, a única diferença entre logado e não será a página exibida quando o trabalho for concluído.

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

Há uma boa pergunta com uma resposta com mais detalhes aqui no SO.


5

Experimente o seguinte trecho, deve ficar bem claro:

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

Isso funcionou para mim, tive que verificar os valores da string de consulta se algum usuário tentar alterar os valores da string de consulta e tentar acessar dados que não estão autorizados para ele / ela, pois estou redirecionando-os para a página de mensagem não autorizada, usando ActionFilterAttribute.
Sameer 23/05

3

Aqui está uma solução que também leva em consideração se você estiver usando solicitações do 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

Isso funciona para mim (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

você pode herdar seu controlador e usá-lo dentro do seu filtro de ação

dentro de sua classe ActionFilterAttribute:

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

dentro do seu controlador de base:

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

Cons. disso é alterar todos os controladores para herdar da classe "MyController"

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.