Part 4 - How to implement custom Forms Authentication in ASP.NET MVC4 application




Introduction

In this post, I am going to implement custom user principal and identity in ASP.NET MVC4 application.
  • In the First part of this series I have implemented very simple and easy authentication.
  • In the Second part of this series I have implemented our custom membership provider to take full control of the database and forms authentication mechanism (like validate user, create user, update user, delete user, change password and more).
  • In Part 3 I have implemented a custom role provider.
  • Now in this part (part 4) We will implement a custom user principal and identity
The IPrincipal and IIdentity are important to authentication and authorization process in .NET. The IPrincipal tells us if the user is authenticated or in a given role and The IIdentity holds information about the user (we can access with "HttpContext.Current.User" Property) . But in the default IIdentity we have only limited information (AuthenticationType, IsAuthenticated and Name) about the user. So, I would like to implement them myself, because it allows me to pass a bit more useful data around in the cookie.

Step-1 : Add a class for extends IIdentity and Implement

Go to solution explorer > Right click on the project name > Add > Class > Enter class name > Add.
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Security.Principal;
            using System.Web;

            namespace MvcAuthentication
            {
                public class MyIdentity : IIdentity
                {
                    public IIdentity Identity { get; set; }
                    public User User { get; set; }

                    public MyIdentity(User user)
                    {
                        Identity = new GenericIdentity(user.Username);
                        User = user;
                    }

                    public string AuthenticationType
                    {
                        get { return Identity.AuthenticationType; }
                    }

                    public bool IsAuthenticated
                    {
                        get { return Identity.IsAuthenticated; }
                    }

                    public string Name
                    {
                        get { return Identity.Name; }
                    }
                }
            }
        

Step-2: Add a class for extends IPrincipal and Implement

Go to solution explorer > Right click on the project name > Add > Class > Enter class name > Add.
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Security.Principal;
            using System.Web;
            using System.Web.Security;

            namespace MvcAuthentication
            {
                public class MyPrincipal : IPrincipal
                {
                    private readonly MyIdentity MyIdentity;
                    public MyPrincipal(MyIdentity _myIdentity)
                    {
                        MyIdentity = _myIdentity;
                    }
                    public IIdentity Identity
                    {
                        get { return MyIdentity; }
                    }

                    public bool IsInRole(string role)
                    {
                        return Roles.IsUserInRole(role);
                    }
                }
            }
        

Step-3: Update Login POST Action code of MyAccountController (created in the part 1).

Here I have replaced the existing code
            [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult Login(Login l, string ReturnUrl = "")
            {

                // Here we will replace our existing code (what I have used in the previous part) used for clear understanding
                #region Existing Code
                //using (MyDatabaseEntities dc = new MyDatabaseEntities())
                //{
                //    var user = dc.Users.Where(a => a.Username.Equals(l.Username) && a.Password.Equals(l.Password)).FirstOrDefault();
                //    if (user != null)
                //    {
                //        FormsAuthentication.SetAuthCookie(user.Username, l.RememberMe);
                //        if (Url.IsLocalUrl(ReturnUrl))
                //        {
                //            return Redirect(ReturnUrl);
                //        }
                //        else
                //        {
                //            return RedirectToAction("MyProfile", "Home");
                //        }
                //    }
                //}
                #endregion
                //Here I am going to use Membership provider to validate user

                #region Part 2 Code
                //if (ModelState.IsValid)
                //{
                //    var isValidUser = Membership.ValidateUser(l.Username, l.Password);
                //    if (isValidUser)
                //    {
                //        FormsAuthentication.SetAuthCookie(l.Username, l.RememberMe);
                //        if (Url.IsLocalUrl(ReturnUrl))
                //        {
                //            return Redirect(ReturnUrl);
                //        }
                //        else
                //        {
                //            return RedirectToAction("Index", "Home");
                //        }
                //    }
                //}           
                #endregion

                #region Part 4 Code
                if (ModelState.IsValid)
                {
                    bool isValidUser = Membership.ValidateUser(l.Username, l.Password);
                    if (isValidUser)
                    {
                        User user = null;
                        using (MyDatabaseEntities dc = new MyDatabaseEntities())
                        {
                            user = dc.Users.Where(a => a.Username.Equals(l.Username)).FirstOrDefault();
                        }

                        if (user != null)
                        {
                            JavaScriptSerializer js = new JavaScriptSerializer();
                            string data = js.Serialize(user);
                            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.Username, DateTime.Now, DateTime.Now.AddMinutes(30), l.RememberMe, data);
                            string encToken = FormsAuthentication.Encrypt(ticket);
                            HttpCookie authoCookies = new HttpCookie(FormsAuthentication.FormsCookieName, encToken);
                            Response.Cookies.Add(authoCookies);
                            return Redirect(ReturnUrl);
                        }
                    }
                }
                #endregion

                ModelState.Remove("Password");
                return View();
            }
        

Step-4: Add Application_PostAuthenticateRequest event in the Global.asax page

            protected void Application_PostAuthenticateRequest()
            {
                HttpCookie authoCookies = Request.Cookies[FormsAuthentication.FormsCookieName];
                if (authoCookies != null)
                {
                    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authoCookies.Value);
                    JavaScriptSerializer js = new JavaScriptSerializer();
                    User user = js.Deserialize<User>(ticket.UserData);
                    MyIdentity myIdentity = new MyIdentity(user);
                    MyPrincipal myPrincipal = new MyPrincipal(myIdentity);
                    HttpContext.Current.User = myPrincipal;
                }
            }
        

Step-5: Edit Layout page for show additional data from HttpContext.Current.User

    <div style="text-align:right;">
    @{
        if (Request.IsAuthenticated)
        {
            var identity = (HttpContext.Current.User as MvcAuthentication.MyPrincipal).Identity as MvcAuthentication.MyIdentity;
            <text>@string.Format("Hello {0}", identity.User.EmailID)</text>
        }
    }
</div>
        

Step-6: Run Application.


How to implement custom Forms Authentication in ASP.NET MVC4 application

Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.