Search code examples
c#asp.net-mvccustom-membershipprovider

Why is this custom identity user context not persisting in MVC?


I created a CustomPrincipal, CustomIdentity, CustomMembershipProvider, etc, and are all populated when a user logs in:

    public class CustomIdentity : IIdentity
    {

        private IIdentity _identity;

        // in the future maybe use a dictionary instead
        //private Dictionary<string, object> _customValues

        private int _userId;
        private bool _IsAuthenticated;
        private string _name;
        private string _displayName;
        private string _role;


        private Website _currentProject;

        public Website CurrentProject
        {
            get { return _currentProject; }
            set { _currentProject = value; }
        }


        private string _userName;

        public string UserName
        {
            get { return _userName; }
            set { _userName = value; }
        }
   ...

All of that works and I can see the values in UserContext.Identity.

However when I try to set UserContext.Identity.CurrentProject = website; and look again later (page reload), the CurrentProject object is null.

I am trying to use the custom UserContext to retain user-specific values, rather than using session objects/variables.

Any ideas as to why this is not retaining the value?

-- UPDATE --

It has been some time since I have looked at this project, and in the Global.asax I found the following:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{

    //var user = HttpContext.Current.User;    // as IPrincipal
    //if (user.Identity.IsAuthenticated)
    //{
    //    // same thing as below
    //}

    //if (Request.IsAuthenticated)
    //{
    //    //get the username which we previously set in
    //    //forms authentication ticket in our login1_authenticate event
    //    string username = HttpContext.Current.User.Identity.Name;

    //    // Retrieves the cookie that contains your custom FormsAuthenticationTicket.
    //    HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    //    // Decrypts the FormsAuthenticationTicket that is held in the cookie's .Value property.
    //    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);

    //    var fromsIdentity = new FormsIdentity(authTicket);

    //    //build a custom identity and custom principal object based on this username
    //    var identity = new CustomIdentity(authTicket);
    //    var principal = new CustomPrincipal(identity);

    //    //set the principal to the current context
    //    HttpContext.Current.User = principal;
    //}

    if (Request.IsAuthenticated) 
    {

        // Retrieves the cookie that contains your custom FormsAuthenticationTicket.
       // HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

        // Decrypts the FormsAuthenticationTicket that is held in the cookie's .Value property.
        //FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);

       // var fromsIdentity = new FormsIdentity(authTicket);

        //build a custom identity and custom principal object based on this username
        //var identity = new CustomIdentity(authTicket);
        //var principal = new CustomPrincipal(identity);

        // TODO: Add checks so we only do the following once per login.

        // Get the GenericPrincipal identity  
        IIdentity ui = HttpContext.Current.User.Identity;  

        /* Extract Name, isAuthenticated, AuthenticationType from
            the identity of the GenericPrincipal and add them including 
            any custom properties to the custom identity. I added a 
            few extra properties to my custom identity. */

        //CustomIdentity customIdentity = new CustomIdentity(ui.Name);

        CustomPrincipal customPrincipal = new CustomPrincipal(ui.Name);

        // Set custom principal 
        HttpContext.Current.User = customPrincipal;

    }

Is some of this on the right track - much of it was commented out.


Solution

  • You have to replace the user on every postback like in this post: http://www.codeproject.com/Tips/574576/How-to-implement-a-custom-IPrincipal-in-ASP-NET-MV

    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();
            if (authTicket.UserData == "OAuth") return;
            CustomPrincipalSerializedModel serializeModel = 
              serializer.Deserialize<CustomPrincipalSerializedModel>(authTicket.UserData);
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.Id = serializeModel.Id;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
            HttpContext.Current.User = newUser;
          } 
    }
    

    This runs on every postback, and thus you have to rebuild the custom identity everytime. For convenience, you can persist the object in session, rather than reload from ticket or DB too.