Where to store logged user information on ASP.NET MVC using Forms Authentication?

29,813

Solution 1

I use this solution:

ASP.NET 2.0 Forms authentication - Keeping it customized yet simple

To summarize: I created my own IPrincipal implementation. It is stored in HttpContext.Current.Cache. If it is somehow lost, I have username from client side authorization cookie and can rebuild it. This solution doesn't rely on Session, which can be easily lost.

EDIT

If you want to use your principal in your controller and make it testable, you can do this:

    private MyPrincipal _myPrincipal;
    MyPrincipal MyPrincipal
    {
        get
        {
            if (_myPrincipal == null)
                return (MyPrincipal)User;
            return _myPrincipal;
        }
        set
        {
            _myPrincipal = value;
        }
    }

In your test, you will set object prepared for testing. Otherwise it will be taken from HttpContext. And now I started thinking, why do I use Ninject to do it?

Solution 2

Store it server side in the session.

Eg.

// Make this as light as possible and store only what you need
public class UserCedentials
{
    public string Username { get; set; }
    public string SomeOtherInfo { get; set; }
    // etc...
}

Then when they sign in just do the following to save the users info:

// Should make typesafe accessors for your session objects but you will
// get the point from this example
Session["UserCredentials"] = new UserCredentials()
    { Username = "SomeUserName", SomeOtherInfo = "SomeMoreData" };

Then whenever you need it fetch it:

UserCredentials user = (UserCredentials)(Session["UserCredentials"]);

I have written a couple of question/answers regarding doing custom authorization in MVC: How to implement authorization checks in ASP.NET MVC based on Session data?

How does the Authorize tag work? - Asp.net Mvc

Solution 3

I actually like to use a CustomPrincipal and CustomIdentity which I set in the logon action method like

        if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password) && _authService.IsValidLogin(username, password))
        {
            User objUser = _userService.GetUserByName(username);
            if (objUser != null)
            {
                //** Construct the userdata string
                string userData = objUser.RoleName + "|" + objUser.DistrictID + "|" + objUser.DistrictName + "|" + objUser.ID + "|" + objUser.DisplayName;
                HttpCookie authCookie = FormsAuthentication.GetAuthCookie(username, rememberMe.GetValueOrDefault());
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
                FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData);
                authCookie.Value = FormsAuthentication.Encrypt(newTicket);
                Response.Cookies.Add(authCookie);
                return RedirectToAction("Index", "Absence");
            }
            else
            {
                return RedirectToAction("LogOn", "Account");
            }
        }
        else
        {
            return RedirectToAction("LogOn", "Account");
        }

Then in the custom principal you can have methods that access specific information you passed in to the constructor like

((CustomIdentity)((CustomPrincipal)HttpContext.Current.User).Identity).DisplayName;

where the DisplayName property is declared in the CustomIdentity class.

Solution 4

Well you will have to store these somewhere. Two main possible places though:

The server

You can either put them into Session. I suggest you do create a separate class that will hold only data that you actually need to avoid of wasting too much memory. Or you can also store into Cache that can end up in having many DB calls when there are huge amounts of concurrent users.

The client

In this case if you can limit the amount of data with a separate class, to that and use whatever way to serialize it and send it to the client. Either in a cookie or in URI (if length permits and cookies are disabled)...

Outcome of these thoughts:
the main thing here would be to create a separate class if you gain much memory resources this way. So that's the first thing you should do.

Share:
29,813
Guillermo Guerini
Author by

Guillermo Guerini

Updated on May 16, 2020

Comments

  • Guillermo Guerini
    Guillermo Guerini almost 4 years

    I'm using ASP.NET MVC and Forms Authentication on my application. Basically I use FormsAuthentication.SetAuthCookie to login and FormsAuthentication.SignOut to logout.

    In the HttpContext.Current.User.Identity I have stored the user name but I need more info about the logged user. I don't want to store my entire User obj in the Session because it might be big and with much more infomation than I need.

    Do you think it's a good idea to create like a class called LoggedUserInfo with only the attributes I need and then add it to the Session variable? Is this a good approach?

    Or do you have better ideas?