Friday, July 3, 2009

Preventing Multiple Login With Same Credentials

Suppose we may want to prevent Multiple login with Same credentials.

For example User A has logged in Machine 1. If the same user A tries to login through the machine 1 through another web browser, the user must get a message: The Person is already logged In.

But how can we maintain this details.

We may be thinking of maintaining the session variables of login credentials and if the user tries to login again, the browser can be closed to prevent the multiple login.

But in case of session maintenance, SQL Server and State Server sessions will never fire Session_End Event in Global.

Only InProc fires the event.

The elegant solution would be Caching with Sliding Expiration as a surrogagte for Session_End Event.

Logic:

1. Cache the UserId and Password when the user logs in with a sliding expiration(Session Timeout).


2. When the user tries to take login again check the Cache Value (UserId and Password Pair plays the key role).

If it matches, throw the Error Message: These Credentials are in use.

3. If the login is successful, update the cache using the expiration limit (session variable).

4. Update the Cache for each page request.

5. If there is no page request for a long time (i.e., more than the interval specified in Session Timeout variable) clears the Cache item , end the session and let the user to login again.



Caching UserId and Password:

We are going to use State Server Session mode to maintain the session details.

Let us say Session["LoginCredentials] to maintain the session key.

The Application_PreRequestHandlerExecute handler in Global, is used to update the Cache,

because the Session object is available and "live" in this handler.


In Global.asax.cs



protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{

//After Initial Login
if(Session["LoginCredentials"]!=null)
{
//Retrieve the key details (UserId and Password)
string sKey=(string)Session["LoginCredentials"];

// Update the Cache Item extends the Sliding Expiration automatically
string sUser=(string) HttpContext.Current.Cache[sKey];

}
}




In LoginPage.aspx

After entering the UserId and Password credentials, validating the details after clicking on Submit button.


private void cmdSubmit_Click(object sender, System.EventArgs e)
{

//validation of user details from database.

SqlCommand cmd = new SqlCommand("Select UserId, Password From UserTable WHERE UserId ='" + txtUserId.Text + "' Password ='" + txtPassword.Text + "'" , connString);

SqlDataReader dr = cmd.ExecuteReader();

If (!dr.Read()) //InValid User Details
{
return;

}

//Valid User Credentials
//Checking for the credentials in the Cache - For multiple login

string sKey= txtUserId.Text + txtPassword.Text; //UserId + Password combination
string sUser=Convert.ToString(Cache[sKey]);

if (sUser==null || sUser==String.Empty){ //No Cache - New Sign In

// Set the cache item and Session timeout

TimeSpan SessTimeOut=new TimeSpan(0,0,HttpContext.Current.Session.Timeout,0,0);

HttpContext.Current.Cache.Insert(sKey,sKey,null,DateTime.MaxValue,SessTimeOut,
System.Web.Caching.CacheItemPriority.NotRemovable,null);

Session["user"] = txtUserId.Text + txtPassword.Text;

Response.Redirect ("Mainpage.aspx", false); //Redirect to Main Page

}
else
{
// cache item exists, User already logged on

lblErrorMsg.Text="These Credentials are in use ";
return;
}


}






We can maintain the Caching and Session details in Sql Server as well as.

One way to set up Cache synchronization among servers is to use SQL Server and have two tables - one with a list of the servers currently active in the web farm, and a second table to hold "Update" information for the cache. This "CacheItems" table would probably need at least three or four columns: a varchar column for the cache "key" (in this case username+password), a DateTime column for current Sliding Expiration value, another DateTime column for Absolute Expiration (if used).

when a session expires in the Cache on one server, you can make an update using the SQL Server to a Cache persistent storage table. This update can made through a WebRequest which is sent to each of the servers on the farm to a special aspx receiver page that is in each app domain. This receiver page basically gets the "notification" and instructs the page to go to the SQL server and update it's resident copy of the Cache from the SQL Server table described above. Each machine would have a page that is capable of handling this process, and thus every machine on the Farm would have the capability both to update the backup store and notify the other webservers, as well as to receive a notification that it needs to retrieve and process the update record(s) from SQL Server.


For more details: http://www.eggheadcafe.com/articles/20030418.asp

No comments:

Post a Comment