How to implement remember me in the login page?

Dondon510 221 Reputation points
2024-01-14T15:00:15.28+00:00

Hi All, How to implement the remember me? what I expect is if the user select the "remember me" then if they logged out and come back again they should not need to enter their user email and password.

I use NetCore 6 C# below, the IsPersistent is true but when the user logout, it goes to login page but it doesn't automatically filled with the last user logged in info.

please help.. thank you


**program.cs**

builder.Services.AddScoped<IUserManager, UserManager>();
builder.Services.AddScoped<IUserRepository, UserRepository>();

builder.Services.AddDbContext<CookieReadersContext>(options =>
{
    options.UseNpgsql(pgSQLConnectionString);
});

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
    options.LoginPath = "/User/Login";
    options.ReturnUrlParameter = "ReturnUrl";
    options.AccessDeniedPath = "/User/Login";
    options.LogoutPath = "/User/Logout";
    options.SlidingExpiration = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(300

);
    options.Cookie.MaxAge = options.ExpireTimeSpan;
});

builder.Services.AddTransient<CustomCookieAuthenticationEvents>();

builder.Services.AddHttpContextAccessor();
builder.Services.AddMemoryCache();

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.Secure = CookieSecurePolicy.Always;
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});

app.UseCookiePolicy();


**login.cs**

public class Login
{
    [Required]
    [EmailAddress]
    [Display(Name = "User Email Address")]
    public string userEmail { get; set; } = "";

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "User Password")]
    public string userPassword { get; set; } = "";

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}


public interface IUserRepository
{
    CookieUserItem Validate(Views.User.Login model);
}

public class UserRepository : IUserRepository
{
    private CookieReadersContext _db;

    public UserRepository(CookieReadersContext db)
    {
        _db = db;
    }

    public CookieUserItem Validate(Views.User.Login login)
    {
       // validate login here
    }
}

public interface IUserManager
{
    Task SignIn(HttpContext httpContext, CookieUserItem user, bool isPersistent);
    Task SignOut(HttpContext httpContext);
}

public class UserManager : IUserManager
{
    public async Task SignIn(HttpContext httpContext, CookieUserItem user, bool isPersistent)
    {
        string authenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;

        // Generate Claims from DbEntity
        var claims = GetUserClaims(user);

        // Add Additional Claims from the Context
        // which might be useful
        // claims.Add(httpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name));

        ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, authenticationScheme);
        ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

        var authProperties = new AuthenticationProperties
        {
            IsPersistent = isPersistent
            // AllowRefresh = <bool>,
            // Refreshing the authentication session should be allowed.
            // ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
            // The time at which the authentication ticket expires. A 
            // value set here overrides the ExpireTimeSpan option of 
            // CookieAuthenticationOptions set with AddCookie.
            // IsPersistent = true,
            // Whether the authentication session is persisted across 
            // multiple requests. Required when setting the 
            // ExpireTimeSpan option of CookieAuthenticationOptions 
            // set with AddCookie. Also required when setting 
            // ExpiresUtc.
            // IssuedUtc = <DateTimeOffset>,
            // The time at which the authentication ticket was issued.
            // RedirectUri = "~/Account/Index"
            // The full path or absolute URI to be used as an http 
            // redirect response value.
        };

        await Models.Users.Update_Last_Login(user.usersPid);
        await httpContext.SignInAsync(authenticationScheme, claimsPrincipal, authProperties);
    }

    public async Task SignOut(HttpContext httpContext)
    {
        await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }

    private List<Claim> GetUserClaims(CookieUserItem user)
    {
        List<Claim> claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.PrimarySid, user.usersPid.ToString()));
        claims.Add(new Claim(ClaimTypes.Name, user.userName));
        claims.Add(new Claim(ClaimTypes.Email, user.userEmail));
        return claims;
    }


**UserController.cs
**
 [HttpPost]
 [Route("/User/Login/")]
 [AllowAnonymous]
 [ValidateAntiForgeryToken]
 public async Task<IActionResult> Login(Views.User.Login login)
 {
     if (login.ReturnUrl == null)
         login.ReturnUrl = "";

     if (!ModelState.IsValid)
         return View(login);

     var user = _userRepository.Validate(login);

     // do some tasks based on returning user
}

[HttpGet]
[Route("/User/Logout")]
public async Task<IActionResult> Logout()
{
    await _userManager.SignOut(this.HttpContext);
    return RedirectPermanent("~/Home/");
}
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,780 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. AgaveJoe 29,786 Reputation points
    2024-01-14T16:38:49.41+00:00

    I use NetCore 6 C# below, the IsPersistent is true but when the user logout, it goes to login page but it doesn't automatically filled with the last user logged in info.

    Correct. The browser's autofill feature is responsible for populating or remembering the user's login not .NET Core.

    https://support.google.com/chrome/answer/95606?hl=en&co=GENIE.Platform%3DDesktop

    0 comments No comments

  2. SurferOnWww 3,796 Reputation points
    2024-01-15T01:27:53.7133333+00:00

    The ASP.NET Core Identity uses a cookie to send the authentication ticket.

    When the user checks the "remember me" checkbox and logs in, the server returns the authentication cookie with expires attribute as follows:

    Set-Cookie: .AspNetCore.Identity.Application=CfDJ8L...i1M; expires=Mon, 29 Jan 2024 00:53:37 GMT; path=/; secure; samesite=lax; httponly

    If the "remember me" checkbox is unchecked, the expires attribute is unspecified in the returned cookie. In this case the cookie becomes a session cookie. A session finishes when the client shuts down, after which the session cookie is removed.

    If the expires attribute is specified, a browser stores the authentication cookie in the HDD or SSD of client's PC so that the cookie will be sent again to the server for a next session even after the browser is closed and opened.

    The logout operation by the user will delete the authentication cookie at the client side. Therefore, the user must login again to obtain the authentication cookie after the logout.


  3. Dondon510 221 Reputation points
    2024-01-15T01:55:06.3866667+00:00

    when logged-out the user will brought to login page but the login page doesn't automatically fill the credentials. when login and remember me is checked, the browser also doesn't offer to save the password or not.

    please help, what I missed here? thank you

    <form class="needs-validation mt-2" novalidate asp-controller="User" asp-action="Login" method="post" autocomplete="off">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    
        <input class="form-control" type="text" asp-for="ReturnUrl" asp-validation-for="ReturnUrl" value="@( Model.ReturnUrl == null ? "" : Model.ReturnUrl )" hidden />
    
        <div class="mb-1">
            <label class="form-label" asp-for="userEmail">Email</label>
            <input class="form-control" type="email" style="text-transform: lowercase" asp-for="userEmail" aria-describedby="login-email" autofocus="true" tabindex="1"   />
            <span asp-validation-for="userEmail" class="text-danger"></span>
        </div>
        <div class="mb-1">
            <div class="d-flex justify-content-between">
                <label class="form-label" asp-for="userPassword">Password</label><a asp-controller="User" asp-action="Forgot_Password"><small>Forgot Password?</small></a>
            </div>
            <div class="input-group input-group-merge form-password-toggle">
                <input class="form-control form-control-merge" type="password" aria-describedby="login-password" asp-for="userPassword" tabindex="2"  />
                <span class="input-group-text cursor-pointer"><i data-feather="eye"></i></span>
            </div>
            <span asp-validation-for="userPassword" class="text-danger"></span>
        </div>
        <div class="form-group mb-1">
            <div class="checkbox">
                <label>
                    <input asp-for="RememberMe" /> @Html.DisplayNameFor(model => model.RememberMe)
                </label>
            </div>
        </div>
        <button type="submit" class="btn btn-page-block btn-primary w-100" tabindex="5">Sign in</button>
        
    </form>
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.