2016-10-13 95 views
6

我有一个名为PasswordChangeChecker.cs的类,它有一个从数据库返回的方法,无论用户是否更改了密码。这个方法的签名是:ASP.NET MVC:如何默认给定一定条件下的页面?

public bool IsPasswordChangedFromInitial(string IdOfUser)

其中IdOfUser是从身份Framework用户ID字段。如果它返回true,则表示不应显示更改密码页面,否则应该导航到更改密码表单。一旦用户成功更改密码,数据库标志就会被适当设置,并且不会再提示他们再次更改密码(除非由管理员手动强制更改)。我怎样才能把这个方法在RouteConfig.cs文件,其中目前我有:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Routing; 

    namespace IdentityDevelopment 
    { 
     public class RouteConfig 
     { 
      public static void RegisterRoutes(RouteCollection routes) 
      { 
       routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

       routes.MapRoute(
        name: "Default", 
        url: "{controller}/{action}/{id}", 
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
       ); 
      } 
     } 
} 

我如何添加一个有条件建设成为defaults参数,这样我就可以使用IsPasswordChangedFromInitial方法来决定是否去密码更改页面?该页面位于/Account/ChangePassword

编辑

按照意见,对于我的具体需要选择相应的操作方法(我省略了不相关的代码):

登录后的操作:

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Login(LoginModel details, string returnUrl) 
      { 

       if (ModelState.IsValid) 
       { 
        AppUser user = await UserManager.FindAsync(details.Name, 
         details.Password); 
        if (user == null) 
        { 
         AppUser userByName = await UserManager.FindByNameAsync(details.Name); 
         if(userByName == null) 
         { 
          ModelState.AddModelError("", "Invalid username."); 
         } 
         else 
         { 
          //If this else is reached, it means the password entered is invalid. 
          //code for incrementing count of failed attempts and navigation to lock out page if needed 

         } 
        } 
        else 
        { 
         if(user.LockedOut) 
         { 
          //navigate to locked out page 
         } 
         else 
         { 
          PasswordChangeChecker PassCheck = new PasswordChangeChecker(); 
          string userId = user.Id.ToString(); 
          bool proceed = PassCheck.IsPasswordChangedFromInitial(userId); 

          //Authorize the user 
          ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user, 
                DefaultAuthenticationTypes.ApplicationCookie); 
          ident.AddClaims(LocationClaimsProvider.GetClaims(ident)); 
          ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident)); 
          AuthManager.SignOut(); 
          AuthManager.SignIn(new AuthenticationProperties 
          { 
           IsPersistent = false 
          }, ident); 

          //persist login into db code 


          if (proceed) 
          { 

           //reset failed logins count 
           return Redirect(returnUrl); 
          } 
          else 
          { 
           return ChangePassword(); 
          } 
         } 


        } 
       } 
       ViewBag.returnUrl = returnUrl; 
       return View(details); 
      } 

ChangePassword()获取操作:

[HttpGet] 
[Authorize] 
public ActionResult ChangePassword() 
{ 
    return View();    
} 

不知何故,返回的视图是RouteConfig.cs而不是ChangePassword.cshtml页面中的视图。 谢谢。

+2

*路由​​用于(良好...)路由。也就是说,将Url与某个控制器/操作进行匹配。你试图完成的任务(强制执行密码策略)更多地属于* Authentication *领域。为什么不在登录时检查'IsPasswordChangedFromInitial()'? – haim770

+0

@ haim770我的确从尝试登录,但我花了很多年试图调试为什么它进入主屏幕,而不是更改密码页,我决定尝试这是最后的手段。 – ITWorker

+0

然后你必须提供更多的代码。您试图保护的控制器/操作是否使用'[Authorize]'属性来修饰? 'AuthorizeFilter'全局注册? – haim770

回答

1

我将与全球行动做它过滤

你可以做一个action filter与方法

protected override void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    if (showChagePwPage) 
    { 
     //redirect to the change password page 
     filterContext.Result = new RedirectToActionResult("ChangePassword", "Account"); 
    } 

    base.OnActionExecuting(filterContext); 
} 

,然后将其添加到全球行动过滤器由

GlobalFilters.Filters.Add(yourFilterContext); 
+0

我没有尝试这个,但感谢替代的想法。 – ITWorker

1

后的数天这个类似于你的地狱般的练习,我试图在登录时路由用户,我意识到我无法在t时间获得UserId的值他登录帐户控制器。我做了一些尝试,并提出了解决我的问题的方法。

我在我的Home控制器中创建了一个ActionResult,并将其命名为Purgatory(当然,一旦它证明有效,我将它重命名为更适合的东西)。在那里,我塞满了所有的登录逻辑,用于在登录后将登录用户路由到各自的页面。

然后,在RedirectToLocal在账户控制器,我改变了

return RedirectToAction("Index", "Home"); 

return RedirectToAction("Purgatory", "Home"); 

当用户登录时,如果returnTo参数是未设置为一个特定的所以现在页面中,returnTo参数将为null,当它到达RedirectToLocal时,它将放弃原来重定向到主页的内容,现在它将进入炼狱。

+0

我也看到了Id被返回null,但不知何故用户名正在通过,所以我继续。但感谢您解释如何处理丢失的Id的方法。 – ITWorker

1

这听起来像是使用动作过滤器的好时机,您可以全局应用或按控制器/动作应用动作过滤器。

这里有一个简单的例子:

using System; 
using System.Web.Mvc; 
using System.Web.Routing; 

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] 
public class VerifyPasswordChangedAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if(!filterContext.ActionDescriptor.ActionName.Equals("changepassword", StringComparison.OrdinalIgnoreCase)) 
     { 
      if (filterContext.HttpContext.Request.IsAuthenticated) 
      { 
       var userName = filterContext.HttpContext.User.Identity.Name; 

       PasswordChangeChecker PassCheck = new PasswordChangeChecker(); 

       if (!PassCheck.IsPasswordChangedFromInitial(userName)) 
       { 
        filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "account", action = "changepassword", area = string.Empty })); 
       } 
      } 
     } 

     base.OnActionExecuting(filterContext); 
    } 
} 

我会修改你的IsPasswordChangedFromInitial方法简单地使用身份验证的用户的用户名,而不是试图找出如何让一个动作过滤器访问UserManager实例。否则,假设您使用的是基于OWIN的ASP.NET身份,请在创建ClaimsIdentity时添加声明以存储该user.Id字段,以便您不必继续查看。

最外面的条件处理这是一个全局过滤器的情况 - 没有它,你会得到一个无限的重定向。

+0

这对于我想实现的目标非常有帮助,因为这是我在重新定向到changpassword之前做的第一步。 – ITWorker