Thursday, 23 February 2017

MVC Implementing FormsAuthentication.

In this article I am showing you the simplest way to implement FormsAuthentication in your MVC application. In this article I am going to use FormsAuthenticationTicket for encrypt and store logged in user data with FormsAuthenticaiton. 


Step 1: Add "authentication mode="Forms"" under <system.web> tag in your web.config file. Modify your web.config file according to following code.

<authentication mode="Forms">
      <forms name="BillAndPayCookie" defaultUrl="/Account/Index" loginUrl="/Account/Index">     </forms>
</authentication>

Step 2: Add new class named LoginModel.cs in your Models folder and paste the following code in this file.
 public class LoginModel
    {
        [Required]
        public string Email { get; set; }
        [Required]
        public string Password { get; set; }
        public string ReturnUrl { get; set; }

        public static void SetCookiesData(LoginModel model)

        {
            FormsAuthentication.SetAuthCookie(model.Email, false);

            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,

           model.Email,
           DateTime.Now,
           DateTime.Now.AddMinutes(30),
           true,
           "{name:'test',password:'123123'}",
           FormsAuthentication.FormsCookiePath);

            // Encrypt the ticket.

            string encTicket = FormsAuthentication.Encrypt(ticket);

            // Create the cookie.

            HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
        }

        public static string DecryptCookie()

        {
            var httpCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

            if (httpCookie == null)

            {
                return "";
            }

            //Here throws error!

            var decryptedCookie = FormsAuthentication.Decrypt(httpCookie.Value);

            if (decryptedCookie == null)

            {
                return "";
            }

            return decryptedCookie.UserData;

        }
    }

Step 3: Add new controller named "AccountController" and paste following code in this.

public class AccountController : Controller
    {
        // GET: Account
        public ActionResult Index(string returnUrl)
        {
            LoginModel model = new LoginModel { ReturnUrl = returnUrl };
            return View(model);
        }

        [HttpPost]

        public ActionResult Login(LoginModel model)
        {
            if (!ModelState.IsValid)
            {
                return View("Index");
            }
            if (model.Email == "sanjay@gmail.com" && model.Password == "sanjay")
            {
                LoginModel.SetCookiesData(model);
                if (!string.IsNullOrEmpty(model.ReturnUrl))
                {
                    return Redirect(model.ReturnUrl);
                }

                return RedirectToAction("Index", "Home");

            }
            else
            {
                ModelState.AddModelError("", "Invalid email or password.");
            }

            return View("Index");

        }

        //[HttpPost]

        public ActionResult Logout()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("Index");
        }
    }

Step 4: Add new view named Index.cshtml for AccountController.

@model BillAndPaySampleMVC.Models.LoginModel
@{
    ViewBag.Title = "Index";
}
<div class="row">
    @using (Html.BeginForm("Login", "Account", null, FormMethod.Post, new { }))
    {
        @Html.HiddenFor(m => m.ReturnUrl)
        <div class="col-md-6 col-md-offset-3">
            <h2>Login</h2>
            <div class="form-group" ng-class="{ 'has-error': form.username.$dirty && form.username.$error.required }">
                <label for="username">Username/Email</label>
                @Html.TextBoxFor(m => m.Email, new { placeholder = "", @class = "form-control" })
            </div>
            <div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required }">
                <label for="password">Password</label><a href="#ForgotPassword" class="btn btn-link">Forgot Password</a>
                @Html.PasswordFor(m => m.Password, new { placeholder = "", @class = "form-control" })
            </div>
            <div class="form-actions">
                <input type="submit" class="btn btn-primary" value="Login" />
            </div>
            <div class="form-actions">
                <span style="color:red">
                    @Html.ValidationSummary()
                </span>
            </div>
        </div>
    }
</div>

Step 5: For the add the roles in every request you need to authenticate every request through Global.asax.cs file. Paste the following method in your Global.asax.cs file.

 protected void Application_AuthenticateRequest(Object sender, EventArgs e)
        {
            if (HttpContext.Current.User != null)
            {
                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    if (HttpContext.Current.User.Identity is FormsIdentity)
                    {
                        FormsIdentity id =
                            (FormsIdentity)HttpContext.Current.User.Identity;
                        FormsAuthenticationTicket ticket = id.Ticket;

                        // Get the stored user-data, in this case, our roles

                        string userData = "admin,user";
                        string[] roles = userData.Split(',');
                        HttpContext.Current.User = new GenericPrincipal(id, roles);
                    }
                }
            }
        }
   
The following method we can use to rename the forms authentication cookie name dynamically.
private static void ResetCookieName(string email)
        {
            // This will enforce that FormsAuthentication class is loaded from configuration settings for the application.
            FormsAuthentication.Initialize();

            // The new cookie name whatever you need can go here, I needed some value from my application setting to be prefixed so I used it.
            string newCookieName = "NewCookieName";

            // Modifying underlying baking field that points to FormsAuthentication.FormsCookieName        
            Type type = typeof(FormsAuthentication);
            System.Reflection.FieldInfo field = type.GetField("_FormsName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            field.SetValue(null, newCookieName);
        }

       

No comments:

Post a Comment