如何在用户点击注销按钮后让用户登录系统并注销?

我正在使用microsoft asp.net身份的自定义实现,因为我有自定义表,这就是为什么我已经给出了我的所有方法IUserStore和IUserPasswordStore的自定义实现。

问题是当用户登录然后在10-15分钟后登录用户会话到期但我想要的是除非用户注销我想让用户登录系统。

码:

public partial class Startup { public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); app.CreatePerOwinContext(ApplicationSignInManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); } } 

账户管理员:

 [Authorize] public class AccountController : Controller { public AccountController() : this(new UserManager(new UserStore())) { } public AccountController(UserManager userManager) { UserManager = userManager; } public UserManager UserManager { get; private set; } [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Login(string email, string password, bool rememberMe = false, string returnUrl = null) { if (ModelState.IsValid) { var user = UserManager.Find(email, password); if (user != null) { await SignInAsync(user, rememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } } return View(); } private async Task SignInAsync(UserModel user, bool isPersistent) { var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); identity.AddClaim(new Claim("FullName", user.FirstName + " " + user.LastName)); identity.AddClaim(new Claim("Email", user.Email)); identity.AddClaim(new Claim("Role", user.Role)); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, ExpiresUtc = DateTime.UtcNow.AddDays(7) }, identity); } private IAuthenticationManager AuthenticationManager { get { return HttpContext.GetOwinContext().Authentication; } } } 

Web.config文件:

           

现在在下面的这行中,我已经给出了7天的到期时间,但是会话在10到15分钟内到期:

  AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, ExpiresUtc = DateTime.UtcNow.AddDays(7) }, identity); 

在我的下面的问题中,您将找到我的UserModel,自定义UserStore类,但为了保持这个小问题,我不在这里放置代码:

UserModel和UserStore

更新 :我已经完全排除了ApplicationUser类,所以现在下面的代码对我来说没用,我想因为这个我的cookie过期了我猜(我仍然不确定):

  public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); app.CreatePerOwinContext(ApplicationSignInManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); } 

注意:**长时间保持会话活动的原因是因为我的mvc应用程序是像Http get调用的角度驱动,Http post调用所以当用户会话过期时我会尝试任何**获取或发布调用然后没有在会话过期的情况下发生,但是当我刷新整个页面时,用户被重定向到登录页面,但直到那时,如果用户不刷新页面,用户将如何知道发生了什么。

你的问题是缺少SecurityStamp 。 安全标记是一个随机字符串,用于检查服务器上是否更改了密码。 安全标记存储在cookie中,现在每次都会根据数据库进行检查。 如果数据库(存储)中的值与cookie中的值不同 – 则要求用户登录。 SecurityStampValidator正在执行所有检查和cookie失效。

您正在为用户使用自定义存储,这很好,但您的存储未实现IUserSecurityStampStore并且当用户登录cookie时未获得SecurityStamp的值。 这会导致SecurityStampValidator出现故障。

所以你的选择是:

  1. 在商店中实施IUserSecurityStampStore
  2. 从配置中删除SecurityStampValidator

由于安全问题,我不喜欢第二种选择。 您希望您的用户永远保持登录状态 – 这意味着cookie永远不会失效。 但是当用户有2个浏览器时,都会登录。 并在其中一个浏览器中更改密码 – 第二个应该注销并要求输入密码。 在不检查安全标记的情况下,第二个浏览器将不会被注销,并且cookie仍然有效。 现在想象第二个浏览器在公共计算机上打开,用户忘记注销 – 即使密码更改,也无法结束该会话。

要实现IUserSecurityStampStore查看合同:

 ///  /// Stores a user's security stamp ///  ///  ///  public interface IUserSecurityStampStore : IUserStore where TUser : class, IUser { ///  /// Set the security stamp for the user ///  ///  ///  ///  Task SetSecurityStampAsync(TUser user, string stamp); ///  /// Get the user security stamp ///  ///  ///  Task GetSecurityStampAsync(TUser user); } 

基本上,这会为您的users表添加另一列: SecurityStamp ,您需要保存一个字符串。 邮票的价值是任意随机字符串。 默认身份implmenetation(第734行)使用Guid.NewGuid().ToString() – 我建议你这样做。

您的用户商店将如下所示:

 public class UserStore : IUserStore, IUserPasswordStore, IUserSecurityStampStore { // your other methods public async Task SetSecurityStampAsync(TUser user, string stamp) { if (user == null) { throw new ArgumentNullException("user"); } user.SecurityStamp = stamp; return Task.FromResult(0); } Task GetSecurityStampAsync(TUser user) { if (user == null) { throw new ArgumentNullException("user"); } return Task.FromResult(user.SecurityStamp); } } 

请注意 – 您无需在此操作中将用户保存到存储中。 UserManagerUpdateSecurityStampAsync为您执行此操作 – 除非您自己覆盖此方法。

另外,在创建新用户时,不要忘记为SecurityStamp字段分配值。 并使用值更新所有现有用户。 像这样的东西将工作update MyUsersTable set SecurityStamp = convert(nvarchar(38), NewId())

在特定时间间隔调用控制器方法,因此它将在evry调用时重置会话超时。 例如,如果最初您已将会话超时设置为30分钟,并且在20分钟后您调用此操作,则会将会话超时重置为30分钟,这样您的会话即使在登录后30分钟仍保持活动状态。

将JQuery代码放在布局中

JQuery的:

 var RefreshSessionInterval; $(document).ready(function () { clearInterval(RefreshSessionInterval); RefreshSessionInterval = setInterval("RefreshSession()", 30000); // change your interval time as per requirement }); function RefreshSession() { $.ajax({ type: "POST", url: '@Url.Action("RefreshSession", "YourControllerName")', success: function (data) { }, error: function () { } }); } 

控制器:

 Public void RefreshSession() { //your session reset from this line, as i know you don't have to write any code here. } public bool LogOut() { LogOff(); return true; } void LogOut() { Session.Clear(); Session.Abandon(); Session.RemoveAll(); ClearCache(); } void ClearCache() { Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1)); Response.Cache.SetNoStore(); ////FormsAuthentication.SignOut(); } 

我有同样的问题,我真的很困惑,因为没有任何理由用户被重定向到登录页面意味着他没有被授权。 我已将超时更改为超过8小时,但没有任何改变。 在阅读了许多页面,例如Aspnet意外注销或频繁意外用户注销后,我发现机器密钥出现问题,并且在检查web.config文件中的机器密钥后,我可以检测到机器密钥的问题。 通过更改机器键并使其与Owin部分中的其他键相同,一切都运行良好。

你有没有尝试过

  ExpireTimeSpan = TimeSpan.FromDays(7); 

所以这会使你的代码:

 public partial class Startup { public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); app.CreatePerOwinContext(ApplicationSignInManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); ExpireTimeSpan = TimeSpan.FromDays(7); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); } } 

您还应该在IIS中的应用程序池级别配置会话超时,如下所述: https : //technet.microsoft.com/en-us/library/cc771956(v = ws.10).aspx

这是我编写用户以保持登录时所做的事情……

 public partial class Startup { public void ConfigureAuth(IAppBuilder app) { // Enable the application to use a cookie to store information for the signed in user app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login") }); // Use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); } } 

账户管理员

 public class AccountController : Controller { ///  /// Initializes a new instance of the  class. ///  public AccountController() : this(new UserManager(new UserStore(new ApplicationDbContext()))) { } ///  /// Initializes a new instance of the  class. ///  /// The user manager. public AccountController(UserManager userManager) { UserManager = userManager; } ///  /// Gets the user manager. ///  ///  /// The user manager. ///  public UserManager UserManager { get; private set; } // // GET: /Account/Login ///  /// Logins the specified return URL. ///  /// The return URL. ///  [AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } // // POST: /Account/Login ///  /// Logins the specified model. ///  /// The model. /// The return URL. ///  [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { var user = await UserManager.FindAsync(model.UserName, model.Password); if (user != null) { await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } } // If we got this far, something failed, redisplay form return View(model); } private async Task SignInAsync(ApplicationUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); } 

或..您还可以在IIS中的应用程序池级别为用户配置会话超时。

会话生存期(会话消失多长时间)和身份validation生命周期(用户必须再次登录多长时间)是两个独立且不同的时间范围。

如果身份validation生命周期长于会话时间范围,则意味着会话将从已经过身份validation的用户开始(即,用户无需登录即可启动会话)。

如果身份validation生命周期短于会话时间范围,则意味着用户将在会话到期之前被强制登录。 当用户重新进行身份validation时,我不确定会话是否“刷新”(可能是猜测…)。

仅为会话和身份validation设置非常长的过期可能不是一个海盗生产就绪解决方案(即会话有很多方法可以“消失”)。

为什么你关心用户的会话是否消失然后启动一个新会话(用户不必登录)? 如果没有关于你想要什么的更多信息,我无法真正理解你的问题的核心。

检查web.config文件的authentication元素中的forms元素的设置。

请注意两个适用设置的默认值。

  1. 超时(默认为30分钟)
  2. slidingExpiration(使用.NET Framework版本的True或False / default varines)

对于您的情况,您可能希望超时持续时间远远高于30分钟,并且slidingExpiration值为True。