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.

ryanzec
fonte

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");
}
CRice
fonte
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.

Syakur Rahman
fonte
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" }

                                         });

    }
}
user2834076
fonte
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.

Tomas Aschan
fonte
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);
  }
}
Muhammad Soliman
fonte
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);
        }
    }
}
Mike
fonte
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();
}
mortenma71
fonte
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"

Muhammad Soliman
fonte