Implementing “Remember Me” Feature In ASP.NET MVC


Recently, I've been working on an MVC 4 web application project where I needed to implement the "remember me" feature on the website. I found two solutions to this problem, and I'd like to share my solution with all of you.

We are implementing the "remember me" functionality on the login page of our ASP.NET MVC project. The first approach involves using the `FormsAuthentication.SetAuthCookie` function, which utilizes the Forms authentication mode.

We are going to implement a "remember me" functionality on the login page of our ASP.NET MVC project. The first approach to achieve this is by using the `FormsAuthentication.SetAuthCookie` function, which utilizes the Forms authentication mode.

We can also do that by creating cookies but just I want to let you know that

If You want make secure web application then should never store the user’s credentials in a cookie. It is un-secure. ASP.Net MVC already gives this functionality securely with Forms Authentication and ASP Membership Providers if you are using the Membership implementation.

You should take the advantage of that. When creating a default Asp .NET MVC project, Visual will include the basic authentication setup and project structure for us. you can use that setup for implementing the remember me feature.

In this Part, I will Explain to you Following Points:-

  • How to implement remember me in Login page in MVC 4 razor?
  • Remember me with login and logout in asp.net mvc
  • How to implement keep me logged in asp.net mvc
  • Formsauthentication setauthcookie in asp net

Using enable forms authentication 

Step:1
Create Database table for user login
Remember feature
public class LoginViewModel
    {
        [Required]
        [Display(Name = "Email")]
        [EmailAddress]
public string Email { get; set; }

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

        [Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
    }
Step:2
Create an Empty Mvc Porject for Login
Step:3
Create Controller,add action method views
ManageAccount.cs
using RememberMe.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace RememberMe.Controllers
{
public class ManageAccountController : Controller
    {
// GET: ManageAccount
public ActionResult Login()
        {
return View();
        }
// GET: ManageAccount
        [HttpPost]
        [AllowAnonymous]
public ActionResult Login(LoginViewModel model)
        {
            DummyDbEntities db = new DummyDbEntities();
string strresponse = string.Empty;
var user = db.Users.Where(a => a.Email == model.Email && a.Password == model.Password).FirstOrDefault();
if (user != null)
            {
//user active
if (user.UserStatus == 1)
                {
                    FormsAuthentication.SetAuthCookie(user.Email, model.RememberMe);
return RedirectToAction("UserProfile");
                }
else
                {
                    strresponse = "Your Account has not been activated.Please connect to admin";
                }
            }
else
            {
                strresponse = "Username or password is incorrect.Please try again!";
            }
            ViewBag.Message = strresponse;
return View();
        }

// GET: ManageAccount/UserProfile
public ActionResult UserProfile()
        {
return View();
        }
        [HttpPost]
public ActionResult Logout()
        {
            FormsAuthentication.SignOut();
return RedirectToAction("Login");
        }
    }
}
ManageAccountController.cs is a C# ASP.NET MVC that handles user authentication and session management.

  • Login(): This method returns a view for the login page. It's the HTTP GET action for displaying the login form.
  • Login(LoginViewModel model): This method handles the form submission when a user tries to log in. It receives a LoginViewModel object containing user input (like email, password, and a flag for "Remember Me"). It checks if the user exists in the database and if the provided email and password match. If successful, it sets an authentication cookie using FormsAuthentication.SetAuthCookie() with the user's email and the "Remember Me" flag. Then, it redirects the user to the "UserProfile" action. If the user is inactive, it displays a message indicating that the account needs activation. If the login fails, it returns the user to the login page with an error message.
  • UserProfile(): This Action method returns a view for the user profile page. It's a used for displaying user-specific information after successful login.
  • Logout(): Handles user logout. It signs out the user by calling FormsAuthentication.SignOut() and redirects them to the login page.
ManageAccountController.cs manages user login, authentication, and logout operations for the web application.

Login.cshtml

@using RememberMe.Models
@model LoginViewModel
@{ 
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")

</head>
<body>
    <div class="container body-content">
        <div class="row">
            <div class="col-md-8">
                <section id="loginForm">
                    @using (Html.BeginForm("Login", "ManageAccount", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                        @Html.AntiForgeryToken()
                        <h4>Use a local account to log in.</h4>
                        <hr />
                        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                        <div class="form-group">
                            @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
                            <div class="col-md-10">
                                @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                            </div>
                        </div>
                        <div class="form-group">
                            @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
                            <div class="col-md-10">
                                @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-md-offset-2 col-md-10">
                                <div class="checkbox">
                                    @Html.CheckBoxFor(m => m.RememberMe)
                                    @Html.LabelFor(m => m.RememberMe)
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-md-offset-2 col-md-10">
                                <input type="submit" value="Log in" class="btn btn-default" />
                            </div>
                        </div>
                    }
                </section>
            </div>
        </div>

        <hr />
    </div>
    @if (@ViewBag.Message != null)
    {
        <script type="text/javascript">
            $(function () {
                alert("@ViewBag.Message")
            });
        </script>
    }
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @*@RenderSection("scripts", required: false)*@
</body>
</html>

UserProfile.cshtml

@using RememberMe.Models
@model LoginViewModel
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")

</head>
<body>
    <div class="container body-content">
        <div class="row">
            <div class="col-md-8">
                <div>
                    @if (Request.IsAuthenticated)
                    {
                        
                        <strong>Welcome @Html.Encode(User.Identity.Name)</strong>
    using (Html.BeginForm("Logout", "ManageAccount", FormMethod.Post))
                        {
                            <a href="javascript:;" onclick="document.forms[0].submit();">Logout</a>
                        }
                    }
    else
                    {
                        <a href="@Url.Action("","")" class="navbar-brand">Login</a>
                    }
                </div>
            </div>
        </div>

        <hr />
    </div>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
</body>
</html>

Step:4
set forms in authentication Web.Config

Add below line in web.config

formauth

 

 <authentication mode="Forms">
      <forms defaultUrl="/ManageAccount/login" loginUrl="/ManageAccount/login" slidingExpiration="true" timeout="2880"></forms>
    </authentication>


ASP.NET web application's web.config file related to forms authentication.

<authentication mode="Forms">: attribute specifies the authentication mode used by the application, which in this case is Forms authentication. Forms authentication allows you to authenticate users based on forms they fill out, typically with a username and password.

defaultUrl="/ManageAccount/login": Specifies the default URL to redirect users to after they've been authenticated. In this case, it's set to "/ManageAccount/login", indicating that users will be redirected to the login page if they try to access a restricted area without logging in first.

loginUrl="/ManageAccount/login": the URL of the login page where users are redirected if they need to authenticate before accessing a protected resource. In this example, it's set to "/ManageAccount/login".

slidingExpiration="true": indicates whether to enable sliding expiration for the authentication ticket. When set to true, it means that the timeout period for the authentication ticket is extended each time a request is made within half the timeout period. This helps keep users logged in as long as they are active.

timeout="2880": sets the timeout period for the authentication ticket, measured in minutes. In this case, the timeout is set to 2880 minutes (48 hours), meaning that users will need to reauthenticate after being inactive for that duration.

sets up Forms authentication for the ASP.NET application, specifying various parameters such as default URLs, expiration settings, and the authentication mode.

if below line present in the config file then remove

Formremove

<remove name="FormsAuthentication" />

Secured way provided by Microsoft,using ASP Membership Providers

  • Create an default Mvc Porject with template
  • It will create the basic template for you with
    login ,registration,remember me feature.
  • Open acccount you can able see the all feature
// POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
    if (!ModelState.IsValid)
            {
    return View(model);
            }

    // To enable password failures to trigger account lockout, change to shouldLockout: true
    var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
    switch (result)
            {
    case SignInStatus.Success:
    return RedirectToLocal(returnUrl);
    case SignInStatus.LockedOut:
    return View("Lockout");
    case SignInStatus.RequiresVerification:
    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
    case SignInStatus.Failure:
    default:
                    ModelState.AddModelError("", "Invalid login attempt.");
    return View(model);
            }
        }


DNBJD

ASP.NET MVC controller and handles the HTTP POST request for user login. 

  • [AllowAnonymous]: allows access to this action even if the user is not authenticated. It's used for login actions where users are not yet authenticated.
  • [ValidateAntiForgeryToken]: helps prevent cross-site request forgery (CSRF) attacks by ensuring that the request includes a valid anti-forgery token.
  • var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);: attempts to sign in the user using the SignInManager.PasswordSignInAsync method. It passes the user's email, password, and a flag indicating whether to remember the user's login. The result is stored in the result variable.
  • SignInStatus.Success: If the sign-in is successful, it redirects the user to the returnUrl or a local URL if returnUrl is null.
  • SignInStatus.LockedOut: If the user's account is locked out due to too many failed login attempts, it returns a view named "Lockout".
  • SignInStatus.RequiresVerification: If the user account requires additional verification, it redirects the user to the "SendCode" action with parameters for returnUrl and RememberMe.
  • SignInStatus.Failure: If the sign-in fails for any other reason, it adds a model error indicating an invalid login attempt and returns the login view with the model.

A standard login action in ASP.NET MVC using Identity framework, which handles user authentication and account lockout features.

Profile page

@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
    using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
    {
    @Html.AntiForgeryToken()

    <ul class="nav navbar-nav navbar-right">
        <li>
            @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
        </li>
        <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
    </ul>
    }
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
        <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}