动作过滤器全局给出Redirect Loop

时间:2017-11-02 14:48:42

标签: c# asp.net-mvc-4 action-filter

我有一个名为LockScreen的类来阻止应用程序。 在阻止屏幕,重新加载页面或通过地址输入页面后,我收到错误,因为我总是进入LockScreen类,然后我得到一个循环。

我该如何解决?我需要始终重定向到LockScreen视图,但我不想要循环。

enter image description here

LockScreen类:

namespace ApplicaAccWeb.Validators
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class LockScreenAttribute : ActionFilterAttribute, IActionFilter
    {
        public static int countLockScreen;
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {

            if (filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                try
                {
                    var lockScreen = filterContext.HttpContext.Session["lockScreen"];

                    if ((string)lockScreen == "Lock")
                    {
                            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
                            new { controller = "Account", action = "LockScreen" }));
                    }

                }
                catch (Exception)
                {

                }
            }
        }
    }
}

的AccountController:

[Authorize]
[LockScreen]
public class AccountController : Controller
{
}

操作GET LockScreen:

public ActionResult LockScreen()
{
    ViewBag.Username = User.Identity.GetUserName();
    this.Session.Add("lockScreen", "Lock");
    return View();
}

动作POST LockScreen:

/// <summary>
/// Permite desbloquear la sesión de un usuario.
/// </summary>
[LogActionFilter]
[HttpPost]
public async Task<ActionResult> LockScreen(string UserName, string Password)
{
    if (!String.IsNullOrEmpty(UserName) && !String.IsNullOrEmpty(Password))
    {
        // No cuenta los errores de inicio de sesión para el bloqueo de la cuenta
        // Para permitir que los errores de contraseña desencadenen el bloqueo de la cuenta, cambie a shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(UserName, Password, false, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                this.Session.Add("lockScreen", "UnLock");
                LockScreenAttribute.countLockScreen = 0;
                return Json(new Dictionary<string, string>() { { "success", "Unlock satisfactorio." } });
            case SignInStatus.LockedOut:
                return Json(new Dictionary<string, string>() { { "error", "Usuario bloqueado." } });
            case SignInStatus.RequiresVerification:
            //return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Contraseña inválida.");
                return Json(new Dictionary<string, string>() { { "error", "Contraseña inválida." } });

        }
    }
    else
    {
        ViewBag.Username = User.Identity.GetUserName();
        return View();
    }
}

FilterConfig类:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    //    filters.Add(new LogActionFilter());
    }
}

2 个答案:

答案 0 :(得分:1)

您尚未将[LockScreen]属性注册为全局操作过滤器,这是正确的做法,但您已在AccountController上使用它。这意味着每次调用Account控制器的任何操作时都会执行[LockScreen]操作过滤器,包括LockScreen操作。因此,当您重定向到LockScreen操作过滤器中的[LockScreen]操作时,会在调用[LockScreen]操作之前再次调用LockScreen操作过滤器;这会导致递归循环。为避免这种情况,请在操作级别定义操作筛选器,并仅针对需要它的操作,而不是在控制器级别。因此,您的帐户控制器应如下所示:

[Authorize]
// Remove the [LockScreen] attribute
public class AccountController : Controller
{
}

相反,将[LockScreen]属性添加到控制器中的所有操作,LockScreen操作除外。

答案 1 :(得分:0)

更新解决方案

创建一个被调用的类:

public class SkipImportantTaskAttribute : Attribute
{
}

将条件添加到我的FilterAction&#34; LockScreenAttribute&#34;:

namespace ApplicaAccWeb.Validators
{

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class LockScreenAttribute : ActionFilterAttribute, IActionFilter
{
    public static int countLockScreen;
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
   /// This is a new Code--------------------------------
            bool skipImportantTaskFilter = filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(SkipImportantTaskAttribute), true) ||
                filterContext.ActionDescriptor.IsDefined(typeof(SkipImportantTaskAttribute), true);

            if (!skipImportantTaskFilter)
            {
                PerformModelAlteration(filterContext);
            }

        }
     ////----------------------------------------------
    }
     ////Only entering here if Bool is true------------------------
    private void PerformModelAlteration(ActionExecutingContext filterContext)
    {
        try
        {
            var lockScreen = filterContext.HttpContext.Session["lockScreen"];

            if ((string)lockScreen == "Lock")
            {
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
                new { controller = "Account", action = "LockScreen" }));
            }
            base.OnActionExecuting(filterContext);
        }
        catch (Exception)
        {

        }
    }
}

}

接下来将[SkipImportantTaskAttribute]添加到我的操作需要忽略

    [HttpPost]
    [SkipImportantTask]
    public async Task<ActionResult> LockScreen(string UserName, string Password)
    {

<强> 重要 @ataravati的解决方案很棒。