Preventing Simultaneous Logons

The other day, I was transacting online with my personal banker while chatting with a friend of MSN Messenger, discussing my plans for the weekend. Suddenly, a thought occurred to me: have you ever tried being online in Messenger from two different computers at the same time?  I’ve tried it and was logged out from the first computer (i.e. the latest logon session is retained and the user is automatically signed out from the other session). This article demonstrates the use of the Cache object in ASP.NET to prevent multiple logons from the same user account to a Web-based system.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 25
April 07, 2004
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Thinking along the same lines, I was really curious about what would happen, if my wife logged on to the same banking system at the same time and transacted. Of course, transaction levels would have been defined properly in the application. However, thinking in terms of nuts and bolts, I was wondering what one could do about it. Can something be done about it at all? Is the crux of the problem really session re-duplication? Or do I have to prohibit the user from simultaneous logons? How? Do I have to track IP addresses? What about all the proxy, firewall, subnet funda?

Thanks to the Cache object in the ASP.NET application framework, I was able to prevent a user from logging on to a system from simultaneous locations. Yes, I was able to prevent two sessions from being created for the same user account.

Does that mean that there is no other solution to this problem? One obvious solution to this problem is to have a flag as part of the user object in the Datastore and toggle it whenever the user logs in and logs out. “Better untaught than ill taught,” goes an old saying. Before proceeding to the Cache based solution, I think it is only fair on my part to explain the above-mentioned solution and discuss its advantages and disadvantages. I would like to refer to this approach as Traditional.

The Traditional Approach

Let us create a Boolean datatype in our database, as part of the User table. I have named it isLogged for the sake of clarity. As soon as the login process, for a given user account, succeeds, the value of this flag would be set to True. Now, let me take a minute to define the success of the login process.

During the login process, as part of verifying the credentials against the User table, we also check for the value of isLogged. If the value is already set to True, it clearly means that the user is already logged on to the system. Aha! Gotcha! We redirect the user to an appropriate page clearly explaining the problem and thus login fails. On the other hand, if the value of isLogged is False, we set it True and allow the user to proceed further with the application.

One of the easier ways to implement this logic is to make use of the global.asax. This file has two routines namely Session_onStart and Session_onEnd. I am sure the names are self-explanatory. So we put the code login process in Session_onStart and set the value of isLogged to False in Session_onEnd. This would be our simple and straightforward logout process.

The Flip Side to It

Ok, now what? The traditional approach would work perfectly under normal scenarios (i.e. a user logs onto our site, has some good time minding their own business and logs out). What will happen if he/she doesn’t log out and just closes the browser; or what if he simply moves on to visit another site without logging out?

One of obvious reasons we can’t trust Session_onEnd is that there is no guarantee that the event will be triggered when the browser is closed.  Does this mean that the entire purpose of Session_onEnd is defeated? Maybe not. The event will be triggered after the session times out. Normally, this time would be set to about 20 minutes. So there are chances that our user gets frustrated and leaves our website once and for all.

Data Caching to Our Rescue

Caching may be defined as the process of keeping information in memory that takes a relatively long time to fetch for quick access the next time it is needed. There are really only two differences between the Application and the Cache objects.

  • The Cache object is thread-safe unlike the Application object, i.e. one doesn’t need to explicitly lock or unlock the Cache collection before adding or removing an item. However, the objects in the Cache collections will still need to be thread-safe themselves.

  • Items in the Cache collection are automatically removed if they expire, if memory in the server becomes limited, or one of their dependent objects or files changes. This means one can freely use the cache without worrying about wasting valuable server memory, as ASP.NET will remove items as needed.

Adding an Object to the Cache collection

There are several ways to insert an item in the Cache collection. You can simply assign it to a key name (as you would with the Session or the Application Collection). But this approach is generally not recommended, as it wouldn’t allow you to control the amount of time the object will be retained in the Cache. A better way of inserting an item into the Cache collection is to use its insert method.

A little on these parameters is in the table below:

Cache.Insert Parameters

Parameter Description
KeyA string that assigns a name to this cached item in the collection.
ItemThe object you want to cache.
 DependenciesA “CacheDependency” object that allows you to create a dependency for this item in the cache. If you don't want to create a dependent item - just specify “Nothing” for this parameter.
AbsoluteExpirationA “DateTime” object representing the time at which the item will be removed from the cache.
SlidingExpirationA “TimeSpan” object represents how long ASP.NET will wait between requests before removing a cached item.
CacheItemPrioritySpecifies how important it is for the cache item to remain in the cache. It can have “AboveNormal”, “BelowNormal”,”Default”, “High”, “Low”, “Normal” or “NotRemovable” as its value.
CacheItemRemovedCallbackThe callback delegate provides a means for you to create your own function that is automatically called when the item is removed from the cache.

Usually we won't use all these parameters at once. For example, we cannot set both a sliding expiration and an absolute expiration policy at the same time. If we want to use an absolute expiration, set the slidingExpiration parameter to TimeSpan.Zero.

Here is an example:


Cache.Insert("testItem"testobjNothingDateTime.Now.AddMinutes(60), TimeSpan.Zero)

Absolute expiration is best recommended in situations when you know the information in a given item can only be considered valid for a specific amount of time. On the other hand, sliding expiration is more useful when you know that a cached item will always remain valid but should still be allowed to expire if not being used.

To set the slidingExpliration policy, set the absoluteExpiration parameter to DateTime.Max as shown below.


Cache.Insert("testItem"testobjNothingDateTime.MaxValueTimeSpan.FromMinutes(10))

The Solution

Getting back on the track of our course, we would be using the cache object with Sliding expiration and Application_PreRequestHandlerExecute of Global.asax to tackle this multiple login issue. As we have seen enough of the theory part, I think its time to look at some source code. For the purpose of testing, let us set the session timeout as 1.

Sample: Global.asax.cs


protected void Application_PreRequestHandlerExecute(Object senderEventArgs e)
{
 
if(Session["UserDetails"]!=null
 
{  
    string strCacheKey 
Session["UserDetails"].ToString();
    string strUser 
HttpContext.Current.Cache[strCacheKey].ToString();
 

}

Sample: Login Page


Private void BtnLogin_Click(object senderSystem.EventArgs e)

string strConCat 
TxtUserName.Text+TxtPassword.Text;
string strUser 
Convert.ToString(Cache[strConCat]);
   
 
if (strUser==null || strUser.Equals(String.Empty))
 
{
    TimeSpan SessTimeOut
=new TimeSpan(0,0,Session.Timeout,0,0);
    Cache
.Insert(strConCat,strConCat,null,DateTime.MaxValue,SessTimeOut,
 CacheItemPriority
.NotRemovable,null);
    
Session["UserDetails"] = strConCat;
    Response
.Write("Welcome!");    
 
}
 else
 
{
    Response
.Write("Duplicate login not allowed !!");
    
return;
 
}
}

That’s it! Easy, isn’t it? (Don’t forget to include System.Web.Caching in the login page). The username is almost always unique so we could even avoid concatenating the username and password.

We can now compile the application and run it. After logging in, if you try to use the same username/password combination the application won’t authenticate you. The only way out is to wait until the Cache expires (I hope you now understand the reason for setting the session time out as 1). This holds good even if we try to login from two different browsers/machines.

Conclusion

The system requirement for testing this sample code is Windows 2000, XP or 2003 OS with IIS 5 (or 6) installed and .NET Framework 1.0. I have omitted the other necessary evils such as text editors! Happy programming!

blog comments powered by Disqus
ASP.NET ARTICLES

- Implementing ASP.NET 4.0 Page.MetaDescriptio...
- ASP.Net Development Tips
- Intro to Sessions in ASP.Net
- Google Maps API Introduction in ASP.NET usin...
- Creating an ASP.NET 3.5 Gridview Image Galle...
- Encrypt QueryString in ASP.NET 3.5 using VB....
- ASP.NET 3.5 Drop Down List Controls
- Connect to Access Database with ASP.Net
- Secure Audio Streaming with ASP.Net and Flash
- Dynamic Sitemap and Navigation in ASP.Net
- Implement Gzip and Deflate Compression in AS...
- Run ASP.Net in Ubuntu with Apache
- ASP.Net Mono Website Contact Forms
- ASP.Net URL Rewriting Methods
- Murach`s ASP.NET 4 Web Programming with C# 2...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 5 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials