ASP.NET MVC中登录用户密码过期全局检查及改密页重定向问题
解决ASP.NET Identity 2中全局密码过期检查的问题
你提到的这个全局特性思路非常合适,要实现它的核心就是在PasswordExpiredAttribute中正确获取UserManager实例,从而拿到用户的PasswordChangedDate属性。下面一步步帮你搞定:
1. 在特性中获取UserManager实例
在ASP.NET Identity 2中,你可以通过Owin上下文来获取UserManager,这是框架默认推荐的直接方式。在过滤器的OnAuthorization方法里,从filterContext.HttpContext提取OwinContext,再从中拿到UserManager:
var userManager = filterContext.HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
这里的ApplicationUserManager是你项目中自定义的UserManager类(通常在IdentityConfig.cs里定义),如果用的是默认模板生成的,也可以直接用UserManager<ApplicationUser>。
2. 完善PasswordExpiredAttribute的完整逻辑
接下来把密码过期检查、重定向的逻辑补全,还要注意避免循环重定向(比如用户已经在修改密码页面时,就不要再触发重定向了):
using System; using System.Web.Mvc; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; public class PasswordExpiredAttribute : AuthorizeAttribute { // 自定义密码过期天数,可根据业务调整 private const int PasswordExpiryDays = 90; public override void OnAuthorization(AuthorizationContext filterContext) { // 先执行基础的授权校验 base.OnAuthorization(filterContext); // 如果用户未认证,或者授权已经失败(比如无权限),直接返回 if (!filterContext.HttpContext.User.Identity.IsAuthenticated || filterContext.Result != null) { return; } // 避免循环重定向:如果当前请求是修改密码的Action,跳过检查 var currentAction = filterContext.ActionDescriptor.ActionName; var currentController = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; if (currentController.Equals("Account", StringComparison.OrdinalIgnoreCase) && currentAction.Equals("ChangePassword", StringComparison.OrdinalIgnoreCase)) { return; } // 获取UserManager和当前登录用户 var userManager = filterContext.HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); var userId = filterContext.HttpContext.User.Identity.GetUserId(); var user = userManager.FindById(userId); if (user != null) { // 计算密码过期时间,判断是否过期 var passwordExpiryDate = user.PasswordChangedDate.AddDays(PasswordExpiryDays); if (DateTime.Now > passwordExpiryDate) { // 重定向到修改密码页面,可携带提示信息 filterContext.Result = new RedirectToRouteResult( new RouteValueDictionary { { "Controller", "Account" }, { "Action", "ChangePassword" }, { "message", "Your password has expired. Please change it to continue using the system." } }); } } } }
3. 注册全局特性,让所有Action生效
要让这个特性对所有Action生效,你需要在Global.asax的Application_Start方法中,把它添加到全局过滤器集合里:
protected void Application_Start() { // 其他初始化代码(路由、区域等)... // 添加全局密码过期检查过滤器 GlobalFilters.Filters.Add(new PasswordExpiredAttribute()); }
这样一来,所有经过授权的请求都会先触发密码过期检查,一旦检测到密码过期,就会强制跳转到修改密码页面。
额外注意事项
- 确保你的
ApplicationUser类中确实包含PasswordChangedDate属性,并且在用户注册、修改密码的Action中,正确更新这个字段(比如设置user.PasswordChangedDate = DateTime.Now)。 - 如果你的项目使用了依赖注入框架(比如Autofac),也可以通过构造函数注入
UserManager,但上面的Owin方式是ASP.NET Identity默认的实现方式,更简单直接。
内容的提问来源于stack exchange,提问作者drv
相关产品推荐
相关产品推荐

