I am implementing an application where there is a mechanic for each machine in the company using the application. I'm trying to implement a user policy whereby if user is in a role "Mechanic" -- with username Machine1, and is logged in for that machine, only one user can be logged at at the same time with the Machine1 username for the company. If someone else tries to login with the same username, it should be blocked and informed that there is already logged in user. When the session timeout expires i should log out the logged in user and free the login to be used. The same happens when the user logouts by himself. I'm trying to build this on asp.net MVC 4 application.
I've thought of using the SessionId, UserId and IsLoggedIn boolean in the database. But in this case i need to change the logged in flag on session timeout in the MVC app to write in the database, which seems overkill if many users are logged in.
What would the implementation be like? What methods or attributes should I be using to handle the session management in the database ?
FYI
I have made my own method where i check if the user is logged in, here it is:
public static bool ValidateUser(string username, string password, string companyName)
{
int? companyId = myRepository.GetCompanyId(companyName);
int? userId = companyId == 0 ? null : myRepository.GetUserId(username, companyId);
if (userId.HasValue && userId.Value != 0)
{
var userKey = Security.GenerateUserKey(username, companyName);
return WebSecurity.Login(userKey, password);
}
else
{
return false;
}
}
Here in this method i can check somehow if the session id is the same as in the database.
I've done similar things and they are always involved. You need a lock or semaphore of some kind. This is best done in the db side with repo actions.
I'm not sure this should count as an actual answer since I'm not giving you an implementation so much as approaches.
approach 1:
Once authenticated, keep the user row-locked with an exclusive lock. Once your user logs out, the repo (EF) connection is recycled, the exclusive lock is freed.
You will need to use a
try-catchon your login process (and possibly use a timeout) as that will be the result of a login attempt.approach 2:
once logged in, lock the user by taking away login permission:
note: this method requires maintenance in assuring that the user is unlocked after logout. This can be tricky. You may choose to use a
destructoraction or a background daemon that checks the last time this user was actually active.approach 3:
have a logged in timestamp on your user record. Update this timestamp everytime the user hits the db for any action.
During login, check the timestamp with a reasonable offset to watch for allowable logging in.
On logout, blank the timestamp.
approach 4
use a
singletonclass: Upon logging in, create an instance with the constructor adding the user's ID (or name) to a static list of users not allowed to login.Use a
destructoraction for removing the user (or go by the existence of an instance of the singleton).Do not allow any logins for users part of the static - singleton driven list.