2016-02-05 59 views
11

我有一个重置密码页面:enter image description here注销用户从浏览器的所有当密码已更改

当用户填写详细信息并点击Reset Password按钮。下面的控制器被称为:

public ActionResult ResetPassword(ResetPassword model) 
{ 
    ... 
    return RedirectToAction("Logout"); 
} 

当用户更改他们的密码,他们从浏览器中得到Logged Out。但是,如果他们在同一时间登录到另一个浏览器,他们仍然登录到其他浏览器。

我想从用户更改密码时登录到的所有浏览器注销用户。

回答

4

因此,我回到家后决定拼凑一些代码。让我看看代码!!!

我会使用一个处理程序,因此验证总是在用户第一次访问应用程序时完成,并且在每个操作方法访问的一个位置完成。

这个想法是,当用户重置他们的密码,应用程序记录用户已重置他们的密码,并没有第一次登录并注销用户。

user.HasResetPassword = true; 
user.IsFirstLoginAfterPasswordReset = false; 

当用户登录时,应用程序将验证用户是否先前已重置密码并且正在首次登录。如果这些语句有效,则应用程序更新其记录以表示您没有重置密码,并且您没有第一次登录。

步骤1

添加两个属性来ApplicationUser模型

enter image description here

步骤2

在Models文件夹添加一类AuthHandler.cs与下面的实施方式。 在此阶段,您验证用户是否已重置密码,并且自密码重置以来第一次未登录。如果是这样,请将用户重定向到登录名。

enter image description here

步骤3

在RouteConfig.cs调用AuthHandler,以便它被调用为每个到来的HTTP请求发送到应用程序。 enter image description here

步骤4

在ResetPassword方法添加实施如下。在此步骤中,当用户重置密码更新要说的属性时,他们重置了密码并且未第一次登录。注意,用户在重置密码时也会显式注销。

enter image description here

步骤5

在登录方法添加以下的实施。在此步骤中,如果用户成功登录,请验证他们的密码已重置,并且他们第一次登录是错误的。如果所有条件均为真,则更新数据库中的属性,以便将来用户重置密码时属性处于准备就绪状态。所以类似的循环决定和更新密码重置的状态,并在重置密码后首先登录。

enter image description here

最后

你AspnetUsers表应该如下

enter image description here

评论

这是我会怎么approa它。我没有测试过,所以如果遇到异常,您可能会修改它。这也是硬编码显示解决问题的方法。

+0

你似乎粘贴了两次相同的图像。另外,我是否错误地认为你的方法只关闭了一个打开的会话,但是如果有更多的会话打开(两个,三个),则会失败 - 第一个打开的会话将重新进行身份验证,但其余的仍然无需身份验证即可运行。 –

+0

@Wiktor谢谢,我更新了图像并添加了一些评论。 –

+0

此方法性能高效 – anand

0

ASP.NET身份验证取决于用户浏览器上的Cookie。因为你使用两个不同的浏览器来测试它。您将拥有两个不同的身份验证Cookie。直到Cookie过期,用户仍然通过身份验证,这就是您获得该结果的原因。所以你将不得不自定义实现。

例如,请务必检查用户是否已重置密码并且尚未使用新密码首次登录。如果他们没有,注销它们并重定向到登录。当他们登录时,一个新的auth cookie将被创建。

+0

得到了自定义实现 – anand

+0

有任何想法。你是使用Entity Framework Code First还是Database First? –

+0

我使用的是EF 6,asp.net 4.5.2,iis-8.5和Identity 2 – anand

0

我模仿我的做法本文从GitHub的博客围绕

Modeling your App's User Session

他们使用Ruby使用​​,但我把它移植到我的ASP.NET MVC项目和工作正常。

用户可以看到所有其他会话并在需要时撤消它们。当用户重置密码时,任何活动会话都将被撤销。

我在基本控制器上使用ActionFilterAttribute来检查活动会话cookie。如果会话cookie被发现陈旧,用户注销并重定向登录。

0

基于CodeRealm的答案...

对于任何人谁经历哪里HTTPS来你的应用程序访问在浏览器上抛出一个空指针异常的情况下(不设置到对象的实例,即对象引用。)这是因为数据库中可能存在HasResetPassWord和/或IsFirstLoginAfterPasswordReset为空的现有记录。Http请求会工作,但https请求会失败,不知道为什么。

解决方案:只需手动更新数据库并提供两个字段值。最好在两列都是错误的。

6

我看到您正在使用ASP.NET Identity 2.您正在尝试执行的操作已经内置。您只需更改SecurityStamp并且所有以前的身份验证Cookie不再有效。

后更改密码,您还需要更改SecurityStamp

await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 
await UserManager.UpdateSecurityStampAsync(User.Identity.GetUserId()); 

如果你希望用户保持登录状态,则必须重新发出一个新的身份验证cookie(登入):

await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 

否则,启动密码更改的用户/会话也将被注销。

,并立即退出其他所有会话,你需要降低在config检查的间隔时间:

app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
    LoginPath = new PathString("/Account/Login"), 
    Provider = new CookieAuthenticationProvider 
    { 
     // Enables the application to validate the security stamp when the user logs in. 
     // This is a security feature which is used when you change a password or add an external login to your account. 
     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
      validateInterval: TimeSpan.FromSeconds(1), 
      regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 
    } 
}); 

重现步骤:

  1. 创建一个新的Asp.Net Web应用程序在VS2015 。
  2. 选择MVC模板。
  3. 编辑App_Stat/Startup.Auth.cs 34行:变化validateInterval: TimeSpan.FromMinutes(30)validateInterval: TimeSpan.FromSeconds(1)
  4. 编辑控制器/ ManageController.cs,管线236:添加UserManager.UpdateSecurityStampAsync方法调用。
  5. 运行项目,创建用户,登录,打开不同的浏览器并登录。
  6. 更改密码,刷新其他浏览器中的页面:您应该注销。
+0

你有没有试过这个方法 – anand

+0

是的。我在上面的答案中添加了_Steps以重现_。这就是我所做的测试。 – Chris

+0

我总是想知道安全印章的用途。感谢您的有用答案! – mem27

0

即使ASP.NET身份验证中明确指出,您必须进行辅助检查以确认用户是否仍然是活动的登录用户(例如,我们可以阻止用户,用户可能更改了他的密码),表单身份验证票证不提供任何安全措施来防止这些情况

UserSession无关与ASP.NET MVC会话,它是在这里

我已实施的解决方案是,

  1. 只是一个名字与UserSessionID (PK, Identity) UserID (FK) DateCreated, DateUpdated数据库创建UserSessions
  2. FormsAuthenticationTicket有一个名为UserData的字段,您可以将UserSessionID保存在其中。在

    public void DoLogin(){ 
    
        // do not call this ... 
        // FormsAuthentication.SetAuthCookie(.... 
    
        DateTime dateIssued = DateTime.UtcNow; 
    
        var sessionID = db.CreateSession(UserID); 
        var ticket = new FormsAuthenticationTicket(
          userName, 
          dateIssued, 
          dateIssued.Add(FormsAuthentication.Timeout), 
          iSpersistent, 
          // userData 
          sessionID.ToString()); 
    
        HttpCookie cookie = new HttpCookie(
         FormsAuthentication.CookieName, 
         FormsAuthentication.Encrypt(ticket)); 
        cookie.Expires = ticket.Expires; 
        if(FormsAuthentication.CookieDomain!=null) 
         cookie.Domain = FormsAuthentication.CookieDomain; 
        cookie.Path = FormsAuthentication.CookiePath; 
        Response.Cookies.Add(cookie); 
    
    } 
    

当用户登录授权用户

的Global.asax类使挂钩到授权

public void Application_Authorize(object sender, EventArgs e){ 
    var user = Context.User; 
    if(user == null) 
     return; 

    FormsIdentity formsIdentity = user.Identity as FormsIdentity; 
    long userSessionID = long.Parse(formsIdentity.UserData); 

    string cacheKey = "US-" + userSessionID; 

    // caching to improve performance 
    object result = HttpRuntime.Cache[cacheKey]; 
    if(result!=null){ 
     // if we had cached that user is alright, we return.. 
     return; 
    } 

    // hit the database and check if session is alright 
    // If user has logged out, then all UserSessions should have been 
    // deleted for this user 
    UserSession session = db.UserSessions 
      .FirstOrDefault(x=>x.UserSessionID == userSessionID); 
    if(session != null){ 

      // update session and mark last date 
      // this helps you in tracking and you 
      // can also delete sessions which were not 
      // updated since long time... 
      session.DateUpdated = DateTime.UtcNow; 
      db.SaveChanges(); 

      // ok user is good to login 
      HttpRuntime.Cache.Add(cacheKey, "OK", 
       // set expiration for 5 mins 
       DateTime.UtcNow.AddMinutes(5)..) 

     // I am setting cache for 5 mins to avoid 
     // hitting database for all session validation 
     return; 
    } 

    // ok validation is wrong.... 


    throw new UnauthorizedException("Access denied"); 

} 

当用户注销

public void Logout(){ 

    // get the ticket.. 
    FormsIdentity f = Context.User.Identity as FormsIdentity; 
    long sessionID = long.Parse(f.UserData); 

    // this will prevent cookie hijacking 
    var session = db.UserSessions.First(x=>x.UserSessionID = sessionID); 
    db.UserSession.Remove(session); 
    db.SaveChanges(); 

    FormsAuthentication.Signout(); 
} 

当用户更改密码或用户被封锁或删除用户...

public void ChangePassword(){ 

    // get the ticket.. 
    FormsIdentity f = Context.User.Identity as FormsIdentity; 
    long sessionID = long.Parse(f.UserData); 

    // deleting Session will prevent all saved tickets from 
    // logging in 
    db.Database.ExecuteSql(
     "DELETE FROM UerSessions WHERE [email protected]", 
     new SqlParameter("@SID", sessionID)); 
} 
+0

我们在谈论ASP.NET身份http://tinyurl.com/h7n9mkb –