Question

I am trying to setup a .NET MVC 3 project to store a custom user session object (which can then be later accessed from a Custom Principal object on other subsequent actions) I have followed the steps here: ASP.NET MVC - Set custom IIdentity or IPrincipal (What LukeP says - i needed the custom membership etc too)

On my login action, I have something like this:


if (provider.ValidateUser(model.UserName, model.Password))
{
        // setup principal 
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        string userData = serializer.Serialize(provider.GetSession());

        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
             1,
             model.UserName,
             DateTime.Now,
             DateTime.Now.AddMinutes(15),
             false,
            userData);

        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);

        if (!String.IsNullOrEmpty(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return RedirectToAction("Index", "Home");
        }
}
else
{
    ModelState.AddModelError("", "The user name or password provided is incorrect.");
}

Which will basically get the user object (provider.GetSession() returns a custom user session object from an external auth service) and then store it in the FormsAuthenticationTicket

Problem is that the User session object from the external service is over 4Kb (its about 7Kb encrypted), and what's happening is that the cookie isn't getting stored in the browser because of the size.

Is there any other safe way to store this user session object somewhere, so i dont have to keep querying the database for it? I have heard that storing it in a Session is unsafe (because of session hijacking - and it being decoupled from membership.) - so what other choice do i have?

I cant reduce the size of the custom user session object - this isnt an option due to its properties being reliant on all system layer calls.

regards, martin

Was it helpful?

Solution

I don't see why you couldn't store it in the user's session object since you should be validating their forms authentication each time they do something privileged.

If you really don't want to store it in their session, you could create a static dictionary and store the data there:

using System.Collections.Concurrent;

// Class level declaration.
static ConcurrentDictionary<string, object> UserData =
        new ConcurrentDictionary<string, object>();

// Inside your magic method.
if (provider.ValidateUser(...)) {
  object providerSession = provider.GetSession();
  string userId = Guid.NewGuid().ToString("n");

  UserData.TryAdd(userId, providerSession);

  FormsAuthenticatonTicket authTicket = new FormsAuthenticatonTicket(
    1,
    model.UserName,
    DateTime.Now,
    DateTime.Now.AddMinutes(15),
    false,
    userid);

  // ...
}

From there, you could then look up your providers session data based on the stored userId in your forms authentication ticket. I made the object stored in the dictionary a standard object since I don't know what your provider returns, so if it's something more specific, be sure to use that class instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top