ASP.NET MVC定义方法xx小时后用户cookie过期时会发生什么

时间:2019-02-20 15:22:33

标签: c# asp.net asp.net-mvc asp.net-mvc-4 cookies

我有一个在用户登录时设置的cookie,如下所示:

 app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/User/Login"),
                CookieName = "LoginCookie",
                ExpireTimeSpan = TimeSpan.FromHours(3),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromHours(3),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

基本上没有什么特别的,它只是用户登录时定义的简单cookie以及持续时间。现在,我想在此处定义一种方法,以了解该Cookie在xx小时(以我的情况为3小时)过期后会发生什么情况。

在这一部分中,我可以看到要定义的方法:

  Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromHours(8),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }

该方法称为“ OnResponseSignOut”,所以我想知道这是否是我想要的吗?

基本上,一旦用户的cookie过期,在将他重定向到登录页面进行重新登录之前,我想将其在数据库中的登录会话更改为“ false”,如下所示:

    var loggedSession = context.LoginSessions.FirstOrDefault(y=>y.UserId == 55 && y.SessionId == Session.SessionID);
   loggedSession.LoggedIn = false;

我怎么能做到这一点?

1 个答案:

答案 0 :(得分:0)

您可以创建 SecurityStampValidator 的副本:

public static class MySecurityStampValidator
{
    private const string DefaultSecurityStampClaimType = "AspNet.Identity.SecurityStamp";

    public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser>(
        TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentity)
        where TManager : UserManager<TUser, string>
        where TUser : class, IUser<string>
    {
        return OnValidateIdentity(validateInterval, regenerateIdentity, id => id.GetUserId());
    }

    public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser, TKey>(
        TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentityCallback,
        Func<ClaimsIdentity, TKey> getUserIdCallback)
        where TManager : UserManager<TUser, TKey>
        where TUser : class, IUser<TKey>
        where TKey : IEquatable<TKey>
    {
        if (getUserIdCallback == null)
        {
            throw new ArgumentNullException("getUserIdCallback");
        }
        return async context =>
        {
            var currentUtc = DateTimeOffset.UtcNow;
            if (context.Options != null && context.Options.SystemClock != null)
            {
                currentUtc = context.Options.SystemClock.UtcNow;
            }
            var issuedUtc = context.Properties.IssuedUtc;

            // Only validate if enough time has elapsed
            var validate = (issuedUtc == null);
            if (issuedUtc != null)
            {
                var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
                validate = timeElapsed > validateInterval;
            }
            if (validate)
            {
                var manager = context.OwinContext.GetUserManager<TManager>();
                var userId = getUserIdCallback(context.Identity);
                if (manager != null && userId != null)
                {
                    var user = await manager.FindByIdAsync(userId).WithCurrentCulture();
                    var reject = true;
                    // Refresh the identity if the stamp matches, otherwise reject
                    if (user != null && manager.SupportsUserSecurityStamp)
                    {
                        var securityStamp =
                                context.Identity.FindFirstValue(DefaultSecurityStampClaimType);
                        if (securityStamp == await manager.GetSecurityStampAsync(userId).WithCurrentCulture())
                        {
                            reject = false;
                            // Regenerate fresh claims if possible and resign in
                            if (regenerateIdentityCallback != null)
                            {
                                var identity = await regenerateIdentityCallback.Invoke(manager, user).WithCurrentCulture();
                                if (identity != null)
                                {
                                    // Fix for regression where this value is not updated
                                    // Setting it to null so that it is refreshed by the cookie middleware
                                    context.Properties.IssuedUtc = null;
                                    context.Properties.ExpiresUtc = null;
                                    context.OwinContext.Authentication.SignIn(context.Properties, identity);
                                }
                            }
                        }
                    }

                    if (reject)
                    {
                        // do what you need
                        var ctx = context.OwinContext.Get<YourDbContext>();
                        var loggedSession = ctx.LoginSessions.FirstOrDefault(y => y.UserId == 55 && y.SessionId == Session.SessionID);
                        loggedSession.LoggedIn = false;
                        ctx.SaveChanges();

                        context.RejectIdentity();
                        context.OwinContext.Authentication.SignOut(context.Options.AuthenticationType);
                    }
                }
            }
        };
    }
}

不要忘记复制ASPNET Identity TaskExtensions 类,因为需要它来保留线程上的区域性:


internal static class TaskExtensions
{
    public static CultureAwaiter<T> WithCurrentCulture<T>(this Task<T> task)
    {
        return new CultureAwaiter<T>(task);
    }

    public static CultureAwaiter WithCurrentCulture(this Task task)
    {
        return new CultureAwaiter(task);
    }

    public struct CultureAwaiter<T> : ICriticalNotifyCompletion
    {
        private readonly Task<T> _task;

        public CultureAwaiter(Task<T> task)
        {
            _task = task;
        }

        public CultureAwaiter<T> GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted
        {
            get { return _task.IsCompleted; }
        }

        public T GetResult()
        {
            return _task.GetAwaiter().GetResult();
        }

        public void OnCompleted(Action continuation)
        {
            // The compiler will never call this method
            throw new NotImplementedException();
        }

        public void UnsafeOnCompleted(Action continuation)
        {
            var currentCulture = Thread.CurrentThread.CurrentCulture;
            var currentUiCulture = Thread.CurrentThread.CurrentUICulture;
            _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() =>
            {
                var originalCulture = Thread.CurrentThread.CurrentCulture;
                var originalUiCulture = Thread.CurrentThread.CurrentUICulture;
                Thread.CurrentThread.CurrentCulture = currentCulture;
                Thread.CurrentThread.CurrentUICulture = currentUiCulture;
                try
                {
                    continuation();
                }
                finally
                {
                    Thread.CurrentThread.CurrentCulture = originalCulture;
                    Thread.CurrentThread.CurrentUICulture = originalUiCulture;
                }
            });
        }
    }

    public struct CultureAwaiter : ICriticalNotifyCompletion
    {
        private readonly Task _task;

        public CultureAwaiter(Task task)
        {
            _task = task;
        }

        public CultureAwaiter GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted
        {
            get { return _task.IsCompleted; }
        }

        public void GetResult()
        {
            _task.GetAwaiter().GetResult();
        }

        public void OnCompleted(Action continuation)
        {
            // The compiler will never call this method
            throw new NotImplementedException();
        }

        public void UnsafeOnCompleted(Action continuation)
        {
            var currentCulture = Thread.CurrentThread.CurrentCulture;
            var currentUiCulture = Thread.CurrentThread.CurrentUICulture;
            _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() =>
            {
                var originalCulture = Thread.CurrentThread.CurrentCulture;
                var originalUiCulture = Thread.CurrentThread.CurrentUICulture;
                Thread.CurrentThread.CurrentCulture = currentCulture;
                Thread.CurrentThread.CurrentUICulture = currentUiCulture;
                try
                {
                    continuation();
                }
                finally
                {
                    Thread.CurrentThread.CurrentCulture = originalCulture;
                    Thread.CurrentThread.CurrentUICulture = originalUiCulture;
                }
            });
        }
    }
}

分配SecurityStamp验证程序:

Provider = new CookieAuthenticationProvider
{
    OnValidateIdentity = MySecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromHours(8),
        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}

您完成了。