需要针对多种不同条件推荐ASP.NET MVC站点上的全局目标重定向

时间:2015-03-12 21:06:32

标签: c# asp.net-mvc authentication model-view-controller

我正在使用ASP.NET MVC应用程序,管理员可以在该应用程序中添加新用户并标记它们以完成其他信息,然后才能使用该网站的其他功能。例如,我们有一个" ForcePasswordReset" bool,以及完成安全问题的要求。我们没有为这些用户使用Active Directory。

最终,这是我想要实施的行为:

  1. 将需要更改密码的任何登录用户指向 ChangePassword视图。如果该用户点击其他链接,则会出现漏洞 他回到了ChangePassword视图。
  2. 必须更改安全问题的用户的相同方案。
  3. 最初,我将检查直接放入Login Controller ActionResult中。但这只是登录操作的原因。缩写代码示例如下。

    public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {    
                // ...
    
                // Does the user need to complete some missing information?
                if (externalUser.IsSecurityQuestionInfoComplete == false)
                    return RedirectToAction("ChangeSecurityQuestions", "MyInfo");
                if (externalUser.ForcePasswordReset)
                    return RedirectToAction("ChangePassword", "MyInfo");
    
                // Login was successful
                return RedirectToLocal(returnUrl);
            }
        }
    

    这种方法的一个问题是在那些目标视图中存在其他超链接,其中用户可以离开目标界面。因此,例如,定向到ChangeSecurityQuestions视图的用户只需点击它即可。

    登录用户可以随时更改这些设置。我可以创建重复的视图来更改仅为此场景设计的密码和安全问题,用户被迫更新这些值。为了保持DRY并减少维护,我想对两种方案使用相同的视图(只想编辑该信息的用户和被迫编辑该信息的用户)。但是,如果替代方案更糟糕的话,试图在这方面保持DRY可能是错误的。

    我开始在帮助器类中编写一个方法来转移这些用户,尝试这样的事情。

        /// <summary>
        /// Check scenarios where the ExternalUser needs to complete some missing information, and divert as necessary.
        /// </summary>
        public static void divertExternalUserAsRequired(Controller controller, ExternalUser externalUser)
        {
            if (externalUser.IsSecurityQuestionInfoComplete == false)
                return controller.RedirectToAction("ChangeSecurityQuestions", "MyInfo");
    
            if (externalUser.ForcePasswordReset)
                return controller.RedirectToAction("ChangePassword", "MyInfo");
        }
    

    但由于保护级别,RedirectToAction无法访问。而且,这似乎不推荐(Is it possible to use RedirectToAction() inside a custom AuthorizeAttribute class?)。而且我不喜欢通过在整个地方粘贴这张支票来控制我的控制器的想法。

    UtilityHelpers.divertExternalUserAsRequired(this, externalUser);
    

    处理此方案的推荐方法是什么?我会更喜欢全局实现的东西,其中检查可以在任何相关视图加载时运行。

    感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

如果我正确理解您的问题,那么您可以选择一些选项。

一种选择是检查Application_BeginRequest课程Global.asax.cs中的必要条件。在每个请求的最开始调用此方法,如果条件失败,则可以加载不同的控制器操作,如下所示:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (!externalUser.IsSecurityQuestionInfoComplete)
        {
            var routeData = new RouteData();
            routeData.Values["action"] = "MyInfo";
            routeData.Values["controller"] = "ChangeSecurityQuestions";

            RequestContext requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);

            IController errorController = new ChangeSecurityQuestionsController();
            errorController.Execute(requestContext);

            requestContext.HttpContext.Response.End();
        }
    }

您可以使用的另一个选项是创建并注册global action filter。正如您在问题中提到的,您不喜欢通过这些条件检查乱丢控制器的想法。通过注册全局操作过滤器,您的控制器可以完全不知道正在对其执行的操作过滤器。您需要做的就是在Global.asax.cs中注册您的操作过滤器,如下所示:

protected void Application_Start()
{
    ...

    GlobalFilters.Filters.Add(new SecurityQuestionCompleteFilter());

    ...
}

我希望这会有所帮助。