0

In ASP.NET MVC, I hold in Session the user object with its privileges, so that I don't have to go to the database each time. So I'm using Session as a cache. eg:

When user logs in:

 User user = dbContext.Users.Include(u => u.Privileges).SingleOrDefault(u => u.UserId == userId)

 Session["CurrentUser"] = user;

When the user does future requests:

 public ActionResult CreateSomething() 
 {
     User user = Session["CurrentUser"];

     if (user == null) 
     {
          // Error: not logged in
     }

     if (!user.Privileges.Any(p => p.PrivilegeId == PrivilegesEnum.CreateSomething)) 
     {
          // Error: doesn't have privilege
     }

     ...
 }

As you can see, that ".Any(...)" will work in memory, which is faster than going to the database.

The problem is that other users can revoke or add privileges to users that are already logged, and these already logged users will perceive these changes only the next time they log in.

 public ActionResult RevokePrivilege(long targetUserId, long privilegeId) 
 {
     ...

     targetUser.Privileges.Remove(privilege)
     dbContext.SaveChanges();

     // ... (*)
 }

Question is: can I access other sessions in (*) so that I can do these changes in memory too?

Something like (I'm inventing here)

        foreach (var kvp in SessionDictionary.Where(kvp => kvp.Value.UserId == user.UserId).ToList())
        {
            SessionDictionary[kvp.Key]["CurrentUser"].Privileges.Remove(privilege);
        }
sports
  • 7,851
  • 14
  • 72
  • 129
  • You need to use `Cache` for storing the user entity and you can use `Session` to store the current user's key. This way you will be able to update the user when the privileges change – Vsevolod Goloviznin Dec 26 '14 at 19:36
  • @VsevolodGoloviznin but `Cache` will be cleared if IIS decides to kill the process? what I like about `Session` is that it wont be cleared if the process dies. – sports Dec 26 '14 at 19:41
  • 1
    @sport the users session cookie will persist, but an InProc session state on the server will be cleared, unless you are using StateServer or Sql. If you are using Sql, you could always dig around in the database directly. For InProc, there seem to be [2 hacks to get at SessionState](http://stackoverflow.com/questions/8854176/get-a-list-of-all-active-sessions-in-asp-net) - Reflection, and binding your own SessionStart subscriber. Possibly keep the user's role(s) in Session, but the actual RolePriviledges in a `Application` level cache? – StuartLC Dec 26 '14 at 19:45
  • @StuartLC If I have session timeout set to 10 minutes: ``, and the process is killed by IIS when the session has been there for 2 minutes, and then the process is started by IIS again (1 minute later), the user will still be there in `Session["currentUser"]`? or it wont? I know the cookie will be. – sports Dec 26 '14 at 19:49
  • @sports you can use an external cache system for that case (like redis), but is getting a user's entity so expensive for you? Moreover, afaik it's not recommended to store large objects in the session object – Vsevolod Goloviznin Dec 26 '14 at 19:49
  • @VsevolodGoloviznin The total users will be less than 10 in the users table, but I don't like the idea of doing a `dbContext.Users.SingleOrDefault(...)` on EVERY request! giving that memory is so much faster. Also I don't want to have an external cache or session provider because I most likely never will have to scale the number of instances ("scale out"). My only problem is that the hosting keeps killing the process when it is idle – sports Dec 26 '14 at 19:52
  • If you use a cache, then you won't hit the table every time. If you have control over IIS, then you can instruct it to not kill idle processes – Vsevolod Goloviznin Dec 26 '14 at 20:01
  • @VsevolodGoloviznin Ah I though that this question: "but is getting a user's entity so expensive for you?" was suggesting me to fetch them directly from the database every time. I don't have control over IIS :( its a shared hosting. – sports Dec 26 '14 at 20:05
  • Well, anyway the best solution you have here is having cache and updating it whenever your permission change. Getting other users sessions may be possible but will require much more effort and you will have to store the mapping between a user and his session token in the cache or anywhere else, so it comes almost to the same thing – Vsevolod Goloviznin Dec 26 '14 at 20:10

1 Answers1

0

Possibly you can access other sessions, but it is unlikely to be easy.

What is easy is to put a timestamp in the session and have it re-load the database content when it expires. This would allow you to have the session data refreshed from the database if it's older than 15 seconds or whatever you set.

Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
Jasen
  • 11,837
  • 2
  • 30
  • 48