![]() |
Web Development »
ASP.NET »
General
Intermediate
License: The Code Project Open License (CPOL)
A better way to implement exclusive login, the account can only be used by one person at the same time.By Jerry.WangThis article brings a better approach to implement the exclusive login in ASP.Net |
C# (C# 2.0), Windows, ASP.NET, Dev
|
||||||||
|
Advanced Search |
|
|
|
||||||||||||||||


English is not my native language, I am not sure whether I can explain my meaning exactly.
In some case, we need exclusive login, that means: the double login is disabled,
the account can only be used by one persion at the same time.
In another word, Two guys can not use the same account at the same time in different place.
I have looked at some popular manners. Usually, people do it in this way.
The session time out set to a small number, like 1 minute.
For the logined user, the session is kept alive by a background timer, Or some else
And the login state is stored in a global place,
when the session started, the login state is inited;
otherwise, if the session ended, the login state is release.
There are some defects in this kind of manner:
1. HTTP connection is not a long-time connection, so if the user close the page,
the Session_End is not triggered immediately. that causes many problem.
If I login one of this kine of site in my Internet Explorer, and then I want to switch to Firefox.
I forget to click the "sign out" link on the page before I close my IE,
then the site won't allow me login in Firefox before the session timed out.
That makes me crazy.
2. If we keep the session alive by a backgroup process.
for example, we use the setTimeout in javascript, and refresh a back-end page every 30 seconds.
That will increase the pressure of the server.
Above all, we need a better way, here I have one:
A.) We always allows account login
B.) We store the latest login session id for the given account in a global place.
C.) We monitor every request, and detect that:
if the current user is signed in but the session id does not equal to the latest session id of this account, kick this user out.
To implement it in this way, we just need extra codes in two places:
a.)login process
b.)PreInit in HttpModule.
Next, I will explain the code
/// <summary>
/// This Hashtable stores the UserID--SessionID Pair
/// The UserID is the key
/// The SessionID is the latest session id for the login user.
/// </summary>
private static Hashtable s_UserID_SessionID_Pair_Collection = new Hashtable();
/// <summary>
/// getter/setter for the userid of current user
/// if the current user does not login in, getter return -1L
/// </summary>
public static long CurrentUserID
{
get
{
if (HttpContext.Current.Session == null ||
HttpContext.Current.Session["CurrentUserID"] == null)
{
return -1L;
}
return (long)HttpContext.Current.Session["CurrentUserID"];
}
set
{
HttpContext.Current.Session["CurrentUserID"] = value;
}
}
Second, in the login process ...
protected void btnLogin_Click(object sender, EventArgs e)
{
//////////////////////////////////////////////////////////////////////////
// login process start
// first, check the username and password; here, always correct
// ... some code to check the username/password ...
// second, get the user id by username from database; here, give a const value
// ... some code to get the user id by username ...
const long userId = 288L;
// third, save state
LoginState.Login(userId);
// finnaly, redirect; here, just keep on the same page
Response.Redirect("Default.aspx");
// login process end
//////////////////////////////////////////////////////////////////////////
}
The LoginState.Login() is detailed here
/// <summary>
/// The user Sign In
/// </summary>
/// <param name="userid">User ID</param>
public static void Login(long userid)
{
CurrentUserID = userid;
s_UserID_SessionID_Pair_Collection[userid] = HttpContext.Current.Session.SessionID;
}
Third, Add a HttpModule class
public class DoubleLoginMonitorModule : IHttpModule
{
public String ModuleName
{
get { return "DoubleLoginMonitorModule"; }
}
public void Init(HttpApplication application)
{
application.PreRequestHandlerExecute += new EventHandler(Application_PreRequestHandlerExecute);
}
private void Application_PreRequestHandlerExecute(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
// if double login, kick it out
if (LoginState.IsDoubleLogin())
{
HttpContext.Current.Response.Redirect("logoff.htm");
HttpContext.Current.Response.End();
}
}
public void Dispose()
{
}
}
The LoginState.IsDoubleLogin() is detailed here
/// <summary>
/// check whether the current user is double login
/// </summary>
/// <returns>true:Yes, the user is double login; false:No</returns>
public static bool IsDoubleLogin()
{
if (CurrentUserID == -1L)
return false;
bool isDoubleLogin = string.Compare( (string)s_UserID_SessionID_Pair_Collection[CurrentUserID]
, HttpContext.Current.Session.SessionID
) != 0;
if (isDoubleLogin)
{
HttpContext.Current.Session.Clear();
HttpContext.Current.Session.Abandon();
}
return isDoubleLogin;
}
Last, modify the web.config, add the HttpModule
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<!-- Add the HttpModule for IIS6 -->
<httpModules>
<add name="DoubleLoginMonitorModule" type="DisableDoubleLogin.DoubleLoginMonitorModule" />
</httpModules>
</system.web>
<!-- Add the HttpModule for IIS7 -->
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules>
<add name="DoubleLoginMonitorModule" type="DisableDoubleLogin.DoubleLoginMonitorModule" />
</modules>
</system.webServer>
</configuration>
It is very simple, isn't it?
For the servers behind load balancing, we need care about:
1. Need keep the session sync, M$ provides several manners, like ASP.Net State Servive.
2. The SessionID--AccountID pair should be stored in a global place, database is a chooice.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 18 Oct 2008 Editor: |
Copyright 2008 by Jerry.Wang Everything else Copyright © CodeProject, 1999-2009 Web17 | Advertise on the Code Project |