ASP.NET - Preventing Multiple Login in Asp.net

Asked By Sally on 13-May-10 05:56 AM
Hi. I'm working on Peter A. Bromberg's article Preventing Multiple Logins in ASP.NET. 
My issue is that if someone closes his browser his session doesn't expire. Then he wants to go back in again. It's not going to let him.. Is there a way to get around that?

Thanks.
Phivos Stylianides replied to Sally on 13-May-10 05:58 AM
Yes there is, use a Global.asax file that contains event for the lifecycle of the page/session. Use the event application-end to track when the application is closed and force the user's session to expire.
Sally replied to Phivos Stylianides on 13-May-10 06:15 AM
I tried it in the

Sub Application_End(ByVal sender As Object, ByVal e As EventArgs) but it's not firing when I close my browser. Am I supposed to be using a different event?

Thanks.

Phivos Stylianides replied to Sally on 13-May-10 06:22 AM
My mistake, the server has to know in some way that the client closed the browser. So using JavaScript you can make a request to the server to end the session on the before unload event of the window. Here is some sample code:
function window.onbeforeunload()  
{
// CHECK IF IE
try
{
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  
xmlhttp.open("GET"," KillSession.aspx",false);  
xmlhttp.send();
}
catch (e)
{}
// REST OF THE BROWSERS
try
{
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","KillSession.aspx",false);
xmlhttp.send();
}
catch (e)
{}  
}

Then in your KillSession.aspx, in the Page_Load event just call the method Session.Abandon() to end the session.
Jinal Desai - LIVE replied to Sally on 13-May-10 06:23 AM
hello sally,

For preventing multiple logins you need to expire session
when user is closing the browser.

To detect the closing event in asp.net
you need to write javascript and call asp.net page methods to
abandon (expire) session.

There are two ways to do so.

1. Either you can directly call .aspx page from unload method of body.

Let's say you wrote in testa.aspx
<body onunload="window.location.href='TestB.aspx';">
Then on testB.aspx you wrote something like following
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
   Call MyBase.OnLoad(e)
 
   ' End The Session
   Session.Abandon()
 
   ' Build A JavaScript String That Will Close This Web Browser Window
   Dim s As String = ""
   s &= "<script language=""javascript"">"
   s &= "window.close();"
   s &= "</script>"
    
   ' Add The JavaScript To The HTML Stream
   Page.RegisterClientScriptBlock("close", s)
End Sub
2. Second method is use javascript function to call .aspx page methods as follows

<body onunload="HandleClose()">
<script language="javascript" type="text/javascript">   //<![CDATA[   function HandleClose()     {      alert("Killing the session on the server!!");       PageMethods.AbandonSession();    }    //]]> </script>

//In code behind You wrote as follows
[WebMethod]
public static void AbandonSession()
 {
   HttpContext.Current.Session.Abandon();
 }

Hope this will help!
Anand Malli replied to Sally on 13-May-10 06:35 AM
Hi Sally

i think what you want is that even if the browser is closed by him/her and now if user wants to open the browser he/she should be logged in

is it the requirement??

as once browser is closed session will be expired but there are alternative ways so just i wanna make sure i am understanding it correctly

thxs

Phivos Stylianides replied to Sally on 13-May-10 06:42 AM
An alternative option is to check a session variable in the Page_Load something like userID and if the user hasn't actually logged out you can bypass the loggin stage and redirect the user to the user page. Many sites do that, in fact it is more common than logging out the user when the browser closes. If you like this idea you can also consider using cookies which you can set to expire after days or even weeks. The same way ebay, google and many others work.
Goniey N replied to Sally on 13-May-10 07:49 AM
Try Below Code :

When Your Application Start At That Time You Have To Set Your Session As Default Or Zero(0).

Session("Login")=0;


Now Check Condition For User That He/She Is Login Or Not.

If Session value Is Zero Then He/She Not Login Means Logout. & If One(1) Then Login.

If (Session("Login") = 0) Then
//Provide To User Login Form...
Response.Redirect("~/Login.aspx")
//In The Login Page When User Will Get Successfully Login Then Set Session("Login")=1 Means Login 
State
Else If (Session("Login") = 1) Then
MsgBox("You Are Already Logged In.")
End If


When User Close Browser Without Logout, Then When He/She Open A Page Then By Default We Will Set It To As Logout Means Session("Login")=0. So He/She Will Be Logged out & Ask Them To Login Again...
Yes, you are correct
Robbe Morris replied to Sally on 13-May-10 07:59 AM
This is a problem you'll run into with no 100% absolute correct way to deal with it in real time without having at least a few exceptions.  What you'll need to do is wire up a timestamp along with the flag in the database that gets updated on every page load.  Then, wire up a scheduled job that runs every minute that reviews your login lock table for remaining locks that may need to be removed.

Plus, you'll want a special admin page that let's a tech support person remove the lock.

I've been through this before with web site applications that earned high dollar license fees and we needed tight restrictions on people sharing username/password combinations to get around paying for extra licenses.  You will need steps like these or you'll run into a lot of support calls.  The other suggestions in this thread will help but they are not full proof.
Sally replied to Robbe Morris on 14-May-10 04:49 AM
Thanks.

How does the scheduled task know when to delete locks from the database?

I just spent some time trying to write a body unload event but I'm running into issues. For example, when the user clicks on response.redirect - it was going to the event that does session.abandon. So, I changed the javascript to only do it when the user presses close, but that wasn't working when the user closes the tab. So, maybe I better stick to this idea with the scheduled task...

Thanks.
Sally replied to Sally on 14-May-10 04:58 AM
I heard of another idea. On unload of the body tag set the session (or the cache object in my case) to expire in 1 minute. Then in every reload - set it to expire in 20 minutes. That way it'll always be expired to 20 minutes so long as the browser is still open.  If they close the browser, it'll expire in 1 minute (maybe I would do 30 seconds). So then if they open a new browser it won't be there anymore.  Do you think that should work?
These are all good steps
Robbe Morris replied to Sally on 14-May-10 09:49 AM
but you cannot rely on whatever mechanism you have in the browser to "always" communicate back to the server that the user has left the session.  You need to have a process that cleans up the login locks on the server at regular intervals along with an admin section on your site to do it manually.

The other method we used to do was simply track logins and ips and look for offenders of our policies.  Granted, it doesn't prevent misuse but it also doesn't upset our clients when they are locked out.  We wrote simple little apps to find likely violations and let a human glance over them once a day.  If something didn't look right, our support team simply called/emailed the client directly to discuss the issue in a polite way.
Sally replied to Robbe Morris on 17-May-10 02:25 AM
Thanks for your help. 

The way I'm doing it is with a cache object that has the sliding expiration date of the session object - so I guess if it doesn't communicate with the server - then it'll automatically expire together with the session object (20 minutes). So, I guess I shouldn't run into too many problems like that. 

If I see that we do, then I'll do the idea of the ip address and have someone check it over. 

Thanks.  
This will fail too
Robbe Morris replied to Sally on 17-May-10 09:06 AM
When the app pool recycles, this event does not always fire.  From my experience, you are still going to leave some locks lying around screwing people up.
Sally replied to Robbe Morris on 25-May-10 05:03 AM
When the app pool recycles, the session won't expire (even after 20 minutes)?

So, is the only way to do it with the database? I didn't want to have to use the database for this..

Thanks.
No, the sessions are lot but
Robbe Morris replied to Sally on 25-May-10 08:31 AM
in my experience the event handled for session end does not "always" fire.  So, as I mentioned above, you have to have other fail safe measures to clear the sign in lock in a reasonable amount of time.  Otherwise, you tick off your users.

I have implemented these types of solutions before and run into all sorts of gotchas depending on certain things to happen with ASP.NET that don't always happen like they should.