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.