Skip to main content

ASP.NET MVC - Set custom IIdentity or IPrincipal

Here's how I do it.
I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.
  1. Create the interface
    interface ICustomPrincipal : IPrincipal
    {
        int UserId { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
  2. CustomPrincipal
    public class CustomPrincipal : ICustomPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  3. CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.
    public class CustomPrincipalSerializeModel
    {
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  4. LogIn method - setting up a cookie with custom information
    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
        serializeModel.UserId = user.Id;
        serializeModel.FirstName = user.FirstName;
        serializeModel.LastName = user.LastName;
    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
    
        string userData = serializer.Serialize(serializeModel);
    
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                 1,
                 viewModel.Email,
                 DateTime.Now,
                 DateTime.Now.AddMinutes(15),
                 false,
                 userData);
    
        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);
    
        return RedirectToAction("Index", "Home");
    }
  5. Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest
    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
    
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.UserId = serializeModel.UserId;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
  6. Access in Razor views
    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)
and in code:
    (User as CustomPrincipal).Id
    (User as CustomPrincipal).FirstName
    (User as CustomPrincipal).LastName
I think the code is self-explanatory. If it isn't, let me know.
Additionally to make the access even easier you can create a base controller and override the returned User object (HttpContext.User):
public class BaseController : Controller
{
    protected virtual new CustomPrincipal User
    {
        get { return HttpContext.User as CustomPrincipal; }
    }
}
and then, for each controller:
public class AccountController : BaseController
{
    // ...
}
which will allow you to access custom fields in code like this:
User.UserId
User.FirstName
User.LastName
But this will not work inside views. For that you would need to create a custom WebViewPage implementation:
public abstract class BaseViewPage : WebViewPage
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}
Make it a default page type in Views/web.config:
<pages pageBaseType="Your.Namespace.BaseViewPage">
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />
  </namespaces>
</pages>
and in views, you can access it like this:
@User.FirstName
@User.LastName

Comments

  1. Helpful link
    http://www.dotnet-tricks.com/Tutorial/mvc/G54G220114-Custom-Authentication-and-Authorization-in-ASP.NET-MVC.html

    ReplyDelete
  2. thank you
    How to use role provider with this code?

    ReplyDelete
  3. once use is authencticated then later in runtime how to set new values to properties of customprincipal class

    ReplyDelete
  4. I think you are confusing the IPrincipal and IIdentity roles; IIdentity tells us who the authenticated user is, while IPrincipal tells us what that user can do. So your identity-specific properties should be on a custom IIdentity, not on the IPrincipal.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I am Getting error the " Object reference not set to an instance of an object." and where i am getting that in contrller
    Var ID = (User as CustomPrinciple).UserID;

    ReplyDelete
  7. This does not work for ApiController, any ideas?

    ReplyDelete

Post a Comment

Popular posts from this blog

Validate credit card number with Mod 10 algorithm in C#

Introduction All you know what information contains in your NIC number. But do you know what information contains in the Credit Card Number? Following article provides brief details about what information contain in your credit card and demonstrates to how to validate credit card number using mod 10 (Luhn) algorithms with C#. Background  Card Length   Typically, credit card numbers are all numeric and the length of the credit card number is between 12 digits to 19 digits.  14, 15, 16 digits – Diners Club 15 digits – American Express 13, 16 digits – Visa 16 digits - MasterCard   For more information please refer  http://en.wikipedia.org/wiki/Bank_card_number . Hidden information  Major Industry Identifier (MII)   The first digit of the credit card number is the Major Industry Identifier (MII). It designates the category of the entry which issued the card.     1 and 2 – Airlin...

Web Services Description Language Tool (Wsdl.exe)

Ref:  https://msdn.microsoft.com/en-us/library/7h3ystb6(VS.80).aspx The Web Services Description Language tool generates code for XML Web services and XML Web service clients from WSDL contract files, XSD schemas, and .discomap discovery documents. wsdl [options] {URL | path} Argument Description URL The URL to a WSDL contract file (.wsdl), XSD schema file (.xsd), or discovery document (.disco). Note that you cannot specify a URL to a .discomap discovery document. Path The path to a local WSDL contract file (.wsdl), XSD schema file (.xsd), or discovery document (.disco or .discomap). Option Description /appsettingurlkey: key or /urlkey: key Specifies the configuration key to use in order to read the default value for the URL property when generating code. When using the   /parameters   option, this value is the   <appSettingUrlKey>   element and contains a string. /appsettingbaseurl: baseurl or /baseurl:...