0

I have many model classes that are mapped from/to tables using EF. Two of them are User and UserCookie, which are stored in tables Users and UserCookies.

public class User
{
    public long UserId { get; set; }
    public string Fullname { get; set; }
    public string Email { get; set; }

    (...)
}

public class UserCookie
{
    public long UserCookieId { get; set; }
    public long? UserId { get; set; }
    public virtual User User { get; set; }
    public string CookieValue { get; set; }
}

Every controller in my ASP.NET MVC application is a child (inherits) of MyController, which is like this:

public class MyController : Controller
{
    protected MyDbContext dbContext;
    protected UserCookie userCookie;
    protected User currentUser;
    protected string cookieValue;

    public MyController() : base()
    {
        this.dbContext = new MyDbContext();
        this.cookieValue = "";
        this.currentUser = null;
        this.userCookie = null;
    }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        HttpCookie cookie = Request.Cookies["LoginCookie"];

        if (cookie != null)
        {
            this.cookieValue = cookie.Value;
            this.userCookie = db.UserCookies.SingleOrDefault(c => c.CookieValue.Equals(cookieValue));

            if (userCookie != null)
                this.currentUser = userCookie.User;
        }
    }

    protected override ViewResult View(string viewName, string masterName, object model)
    {
        ViewBag.CurrentUser = currentUser;
        ViewBag.UserCookie = userCookie;
        ViewBag.CookieValue = cookieValue;

        return base.View(viewName, masterName, model);
    }
}

When the user sign in successfully, I create a cookie in him with a random value, like this:

   public ActionResult Login(...) 
   {
        (...)

        HttpCookie cookie = new HttpCookie("LoginCookie");
        cookie.Value = Guid.NewGuid().ToString();
        Response.Cookies.Add(cookie);

        userCookie.User = user;
        userCookie.CookieValue = cookie.Value;
        db.UserCookies.Add(userCookie);

        db.SaveChanges();

The problem with all this that I've shown is that I'm doing a request to the database in every HTTP request (that is, in every call to one of my actions).

I'm also not happy with the table UserCookies because it has to be cleaned and is not intuitive. Also the generated Guid is not safe.

I know how wrong is all this, but... I can't figure out an elegant way of achieving the same benefits.

The main benefit of this is that I have access to currentUser in every action, so I can do stuff like this easily:

    if (!currentUser.Privileges.Any(p => p.Privilege == PrivilegesEnum.Blah))
    {
         (...)
    }

I also have access to currentUser in all of my views.

Questions:

  1. What is the most common way of achieving this in real professional software?
  2. If I wanted to use cache (like Redis), do I have to change a lot of stuff in the presented scenario?
  3. If I do use cache, should I store just the userId instead of the entire User object?
1

You should never trust a plain text cookie as a source of record for user details as they are easily modifiable. Doing so will leave you exposed to spoofing type of vulnerabilities. You can protect against this by using encryption or signing, but I'd leave the details of that to a library if you can as implementation details of doing so can be tricky.

Typically what is done is only a user identifier is sent to the database, like a primary key or a unique guid. Rather than generating a new guid every time just add a field to the user table in the database. Send this in a signed cookie or throw it in a session server (Redis works well for this). If you need the user details for rendering, just throw the user object in your cache and look it up by this identifier.

Basically what you have implemented above is a light weight implementation of ASP.NET's DB Session Server.

The other option is using some sort of Single Sign On system with XML claims, but it is likely overkill for what you want.

  • What library for encryption/signing would a professional software (that is made with ASP.NET MVC4) use? – sports Sep 3 '14 at 20:22
  • Something like this would work: stackoverflow.com/questions/6845275/… There is also an implementation in .NET but it is marked as internal, so you can not use it directly. – brianfeucht Sep 4 '14 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.