2

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!!

Philiz
  • 429
  • 5
  • 25

1 Answers1

1

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...
    }

}
Rena
  • 30,832
  • 6
  • 37
  • 72
  • Thank you. But how can I know in the function "ValidatePrincipal(...)" if the session server-side has expired? In this case, I need to get the user Id from the cookie, query the DB to get the user info, create the userPrincipal according to that info, and then call once again HttpContext.SignInAsync(userPrincipal,...). (I've update the question to be more clear.) – Philiz Feb 04 '21 at 12:54
  • For how to check the cookie expired,please check my updated answer. – Rena Feb 05 '21 at 02:47
  • Thanks but here you are checking the cookie expiration date. In my problem, the cookie will be still valid, BUT the session server side will not be present anymore. My question is: how can I check that the session is still present or not for that cookie? – Philiz Feb 05 '21 at 07:20
  • Hi @Philiz,you may misunderstand seesion and cookie.The session expired time will not influence the cookie.So although the session has been expired,the cookie is still valid,it is correct action. – Rena Feb 05 '21 at 07:55
  • Thanks, so you mean that all information that I put in the "userClaims" at the login time is present in the cookie. And I don't need to fetch it again if the server session has expired? I will then be able to call anywhere in the application "User.GetIdOrganisation()" and have the correct value? – Philiz Feb 05 '21 at 12:16
  • Hi @Philiz,that's it .Session expired will not influence cookie expired.But not sure what is your "User.GetIdOrganisation()" method. – Rena Feb 08 '21 at 01:30
  • Sorry, User.GetIdOrganisation() is actually an extended method of the claimsPrincipal class. I'm actually doing "claimsPrincipal.Claims.FirstOrDefault(x => x.Type == "id_organisation")". I did some tests, it seems I can get this info correctly even after the server session has expired. – Philiz Feb 08 '21 at 08:43