Search code examples
asp.net-core-mvcsession-cookiesclaims-based-identity

Implement "Remember me" in ASP.NET CORE 3.1 MVC


I can't figure out how to add the functionality of "Remember me" while logging in the website ASP.NET CORE 3.1 MVC according to the code I have below. Where and how should I check if the session on server side has expired and, in this case, load the user info from the DB according to the cookie?

Practical example: A user logs in (with "Remember me" checked) and comes back on the website 1 week later. In the meantime, the session on the server has expired. I would like the user to be automatically logged in when the user comes back.

Code executed server side when logging with "Remember me" checked:

var userClaims = new List<Claim>()
{
     new Claim("id", user.Id.ToString()),
     new Claim("id_organisation", user.Id_organisation.ToString())
};

var grantMyIdentity = new ClaimsIdentity(userClaims, "User Identity");
var userPrincipal = new ClaimsPrincipal(new[] { grantMyIdentity });
await HttpContext.SignInAsync(userPrincipal, new AuthenticationProperties
{
       IsPersistent = true,
       ExpiresUtc = DateTime.UtcNow.AddMonths(1)                          
});

In the Startup.cs I have:

public void ConfigureServices(IServiceCollection services)
{
     ...
     TimeSpan expiration_cookie_and_session = TimeSpan.FromHours(2);
     services.AddAuthentication("CookieAuthentication")
             .AddCookie("CookieAuthentication", config =>
              {
                  config.Cookie.Name = "UserLoginCookie";
                  config.LoginPath = "/connexion";
                  config.SlidingExpiration = true;
                  config.ExpireTimeSpan = expiration_cookie_and_session;
                  config.EventsType = typeof(MyCookieAuthenticationEvents);
              });
     services.AddScoped<MyCookieAuthenticationEvents>();
     services.AddSession(options => {
              options.IdleTimeout = expiration_cookie_and_session;
         });
      ...
 }

public class MyCookieAuthenticationEvents : CookieAuthenticationEvents
{
    //We are here in case of cookie expiration
    public override Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> redirectContext)
    {
     ...
    }
}

My guess would be in the CookieAuthenticationEvents.OnSigningIn event. Can you help me to make it clear? Thank you!!


Solution

  • You could get the cookie expire time by using:context.Properties.ExpiresUtc.

    If you want to get the expire time in the other request after login successfully,you could add the expire time to HttpContext in ValidatePrincipal method.Once you sign in successfully and get into another action,it will hit the ValidatePrincipal method to add the expire time to HttpContext.

    Custom CookieAuthenticationEvents:

    public class MyCookieAuthenticationEvents : CookieAuthenticationEvents
    {
    
        public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
        {
            context.Request.HttpContext.Items.Add("ExpiresUTC", context.Properties.ExpiresUtc);
    
        }
    }
    

    Get the expire time in the action:

    public async Task<IActionResult> Index()
    {
        var expiretime = HttpContext.Items["ExpiresUTC"];
                  
        return View();
    }
    

    Result:

    enter image description here

    Update:

    For how to judge the cookie expired:

     public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
    
        context.Request.HttpContext.Items.Add("ExpiresUTC", context.Properties.ExpiresUtc);
        //Compare() method Return value Meaning
        //Less than zero means first is earlier than second. 
        //Zero means first is equal to second. 
        //Greater than zero means first is later than second.
        var calculte = DateTimeOffset.Compare((DateTimeOffset)context.Properties.ExpiresUtc, DateTimeOffset.Now);
        if(calculte<0)
        {
            // the cookie has been expired
            //do your stuff...
        }
    
    }