views:

5331

answers:

3

I need to do something fairly simple: in my ASP.NET MVC application, I want to set a custom IIdentity / IPrincipal. Whichever is easier / more suitable. I want to extend the default so that I can call something like User.Identity.Id and User.Identity.Role. Nothing fancy, just some extra properties.

I've read tons of articles and questions but I feel like I'm making it harder than it actually is. I thought it would be easy. If a user logs on, I want to set a custom IIdentity. So I thought, I will implement Application_PostAuthenticateRequest in my global.asax. However, that is called on every request, and I don't want to do a call to the database on every request which would request all the data from the database and put in a custom IPrincipal object. That also seems very unnecessary, slow, and in the wrong place (doing database calls there) but I could be wrong. Or where else would that data come from?

So I thought, whenever a user logs in, I can add some necessary variables in my session, which I add to the custom IIdentity in the Application_PostAuthenticateRequest event handler. However, my Context.Session is null there, so that is also not the way to go.

I've been working on this for a day now and I feel I'm missing something. This shouldn't be too hard to do, right? I'm also a bit confused by all the (semi)related stuff that comes with this. MembershipProvider, MembershipUser, RoleProvider, ProfileProvider, IPrincipal, IIdentity, FormsAuthentication.... Am I the only one who finds all this very confusing?

If someone could tell me a simple, elegant, and efficient solution to store some extra data on a IIdentity without all the extra fuzz.. that would be great! I know there are similar questions on SO but if the answer I need is in there, I must've overlooked. Thanks.

+17  A: 

I can't speak directly for ASP.NET MVC, but for ASP.NET Web Forms, the trick is to create a FormsAuthenticationTicket and encrypt it into a cookie once the user has been authenticated. This way, you only have to call the database once (or AD or whatever you are using to perform your authentication), and each subsequent request will authenticate based on the ticket stored in the cookie.

A good article on this: http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html

John Rasch
Right, that was what I needed. Funny enough, I didn't read much about creating your own ticket and passing data. Thanks!
Razzie
+12  A: 

Here is an example to get the job done. bool isValid is set by looking at some data store (lets say your user data base). UserID is just an ID i am maintaining. You can add aditional information like email address to user data.

      protected void btnLogin_Click(object sender, EventArgs e)
        {         

        //Hard Coded for the moment
        bool isValid=true;
        if (isValid) {
                    string userData = String.Empty;
                    userData = userData + "UserID=" + userID;
                    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(30), true, userData);
                    string encTicket = FormsAuthentication.Encrypt(ticket);
                    HttpCookie faCookie =new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
                    Response.Cookies.Add(faCookie);
                    // And send the user where they were heading
                    string redirectUrl =FormsAuthentication.GetRedirectUrl(username, false);
                    Response.Redirect(redirectUrl);
                }
                }
}

in the golbal asax add the following code to retrive your information

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookie[
             FormsAuthentication.FormsCookieName];
    if(authCookie != null)
    {
        //Extract the forms authentication cookie
        FormsAuthenticationTicket authTicket = 
               FormsAuthentication.Decrypt(authCookie.Value);
        // Create an Identity object
        //CustomIdentity implements System.Web.Security.IIdentity
        CustomIdentity id = GetUserIdentity(authTicket.Name);
        //CustomPrincipal implements System.Web.Security.IPrincipal
        CustomPrincipal newUser = new CustomPrincipal();
        Context.User = newUser;
    }
}

When you are going to use the information later, you can access your custom principal as follows.

(CustomPrincipal)this.User
or 
(CustomPrincipal)this.Context.User

this will allow you to access custom user information.

Have fun, Sriwantha Sri Aravinda

Sriwantha
Thanks. I was particularly looking for the FormsAuthenticationTicket. It's easy once you know how!
Razzie
FYI -- it's Request.Cookies[] (plural)
Dan Esparza
Don't forget to set Thread.CurrentPrincipal as well as Context.User to the CustomPrincipal.
Russ Cam
A: 

Are you sure with this?

System.Web.Security.IIdentity
System.Web.Security.IPrincipal
Fleents
Answer in the form of a question -1
almog.ori