views:

219

answers:

7

I have implemented my own custom MembershipProvider with a custom data store. No problems so far. I would like for people to login using their email instead of a username. Because I have my own data store, this is not a major issue, I can just pass the email as the username for the MembershipProvider.

My question is, how do I store additional custom user data along in the FormsAuthenticationTicket? I want to store a couple of things that will never change, such as their UserId, First/Last Name and Country. I started looking into creating FormsAuthenticationTicket with the UserData, but quickly got confused. How do I store multiple things into this UserData, and how do I easily read this data back on every single ASP.NET MVC2 page. I found many samples, none that really seemed that great in terms of MVC2. There has to be a simple way to do this.

It would make no sense to read the UserId, First/Last Name and the Country from a database on each and every request because it would never change. Plus, while I want the user to login using their email, I'd want to store their UserId in the auth cookie so that it can be used in nearly every user related database query rather than the email (because in all the tables, the user data is stored along with the UserId - not the email because technically the email could be changed - I already figured that stuff out when it comes to the MembershipProvider).

What is the best practices for storing additional user data like this in ASP.NET MVC2?

+1  A: 

Hey,

Just store it separately yourself. All forms auth does is store it in a cookie and encrypt/decrypt on the server. You can encrypt/decrypt the data yourself. You can also use other stores like disk I/O or cache, so you aren't storing anything on the client.

HTH.

Brian
I would like to store these few things on the client if possible, because this web application will be hosted on many servers, users are not guaranteed to end up on the same server again. I realize that I can store this in my own (encrypted) cookie, but figured it may make more sense to put it in the auth cookie? This way I dont have to manage two cookies. Plus, I would like to read the values using User.Identity.something or something similarly simple.
Stefan
What happens when one of your users gets married?
Simon Hazelton
The data I want to put in the auth cookie will not change during the session. First/Last name will be able to be changed in the database (where the data is loaded from once when the user logs in). It would correctly populate next time the user logs in. This behaviour is expected.
Stefan
I don't think a separate cookie is that big of a deal personally... it's easier to create your own structures rather than be dependent on the .NET components/framework/setup.
Brian
+1  A: 

How about using Session for that?

uvita
I forgot to mention that this web application needs to be highly scalable for use with hundreds of thousands of users. Because the application will run on many servers (not in affinity), I am trying to avoid using Session variables.
Stefan
A: 

I would use Profile to store custom user information, it is, after all, what it was designed for :)

ASP.Net Profile

And if you need to store the information in a more SQL structured format, use a Custom Profile Provider

In your custom profile you could implement caching and I'm sure that you could scale this out to a huge number of users.

Simon Hazelton
Ideally I would like to avoid having to query a database on each and every request just to get basic information such as UserId, Name and Country. These few things should be able to be stored on the client (encrypted in the auth cookie for example). This would be much more scalable.
Stefan
The only fixed piece of data there is the userId. I think you need to evaluate the balance between scalability and manageability. People and their information are very transient. What will happen if you want to change the information set in the future?
Simon Hazelton
The information can be changed but would not update in the auth cookie until the next login.
Stefan
Don't touch the cookie or whatever you put there can be compromised and is unreliable. Encrypting/decrypting doesn't come cheap either. Store your user's prefs server-side, in a profile. It's designed to be fast.
Jeroen
+1  A: 

The FormsAuthenticationTicket cookie has an UserData property you can store whatever you want in. I throw JSON serialized object graphs in there for caching user related stuff like Last,First names or additional role information.

There are some size limits but as long as your sensible you should be ok.

jfar
A: 

Profile is the best way to store custom user specific data. All you have to do is create the fields in the web.config page, then reference them just like session state variable. Session State is good for data that is persistant during 1 session (hence the name).

Web.Config:

    <profile>
        <properties>
            <add name="DepartmentNumber"/>
        </properties>
    </profile>

Save to profile:

ProfileCommon newProf = Profile.GetProfile(username);
                newProf.DepartmentNumber = "12";   //Or whatever string data you have.
                newProf.Save();

Reference:

String departmentNumber = Profile.DepartmentNumber;    //Data is stored as String.
Marc
A: 

If your concerned about round-trip queries each time you need this data, then do a combination of Session State and Profile. Store the data in a profile, and then after your login succeeds, grab those values into Session State. Use them from Session State during that session. You could even add a check which would query the Profile if the session state is empty.

Marc
A: 

Hi,

This post shows (among other things) the details of storing in FormsAuthenticationTicket.UserData and reading it from a base controller. http://www.west-wind.com/weblog/posts/899303.aspx

As someone suggested above, a simple data class that holds all the info needed and a pair of serialize/deserialize methods will do the job.

    public class UserState
    {
        public int Id { get; set; }

        public Guid ActivationId { get; set; }
        public string UserName { get; set; }
        public string Email { get; set; }
        public bool IsAdmin { get; set; }

        // Serialize    
        public override string ToString()
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string result = serializer.Serialize(this);
            return result;
        }

        // Deserialize
        public static UserState FromString(string text)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Deserialize<UserState>(text);
        }
    }
}
Germán