我有一个名为PasswordChangeChecker.cs
的类,它有一个从数据库返回用户是否更改了密码的方法。该方法的签名是:
public bool IsPasswordChangedFromInitial(string IdOfUser)
其中IdOfUser
为Identity框架User的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
编辑
根据注释,适合我特定需求的操作方法是(我省略了不相关的代码):
Login post action:
[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() get action:
[HttpGet]
[Authorize]
public ActionResult ChangePassword()
{
return View();
}
返回的视图是RouteConfig.cs
而不是ChangePassword.cshtml
页面中的视图。谢谢你。
我会使用全局动作过滤器
你可以用方法
创建一个动作过滤器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);
经过几天类似于您的这种地狱般的练习后,我试图在登录时路由用户,我意识到我将无法在登录Account控制器时获得UserId的值。我做了一些实验,想出了这个方法,解决了我的问题。
我在我的Home控制器中创建了一个ActionResult,并将其命名为Purgatory(当然,当它被证明具有功能时,我将其重命名为更合适的名称)。在这里,我填充了所有登录逻辑,以便在登录时将登录用户路由到各自的页面。
然后,在帐户控制器中的redirecttollocal中,我更改了return RedirectToAction("Index", "Home");
return RedirectToAction("Purgatory", "Home");
所以现在当用户登录时,如果returnTo参数没有设置为特定的页面,则returnTo参数将为空,当它到达redirecttollocal时,它将下降到以前的主页重定向,现在将进入炼狱。
这听起来是使用动作过滤器的好时机,您可以全局或每个控制器/动作应用它。
下面是一个简单的例子:
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 Identity,当你创建ClaimsIdentity
时,添加一个声明来存储user.Id
字段,这样你就不必一直查找它了。
最外面的条件处理全局过滤器的情况—没有它,您将获得无限重定向。