Click here to Skip to main content
6,306,412 members and growing! (22,227 online)
Email Password   helpLost your password?
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.Wang

This article brings a better approach to implement the exclusive login in ASP.Net
C# (C# 2.0), Windows, ASP.NET, Dev
Posted:18 Oct 2008
Views:6,902
Bookmarked:31 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
10 votes for this article.
Popularity: 3.74 Rating: 3.74 out of 5

1
3 votes, 30.0%
2

3
3 votes, 30.0%
4
4 votes, 40.0%
5



2.jpg

Introduction 

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.
 

Background

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

Using the code

First, we need some variables.
        /// <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>

Afterword

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jerry.Wang


Member
Jerry is working for the Clochase.Inc, located in ChangSha, China. He has been being interested in computer programing from his childhood. Skilled in Windows/Linux C++, Mac OS Objective-C, .Net & C#, ASP.Net, AS3/JS/LUA etc.
Occupation: Architect
Company: Clochase.Inc
Location: China China

Other popular ASP.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
GeneralGood article PinmemberDonsw14:17 28 Jan '09  
GeneralRe: Good article Pinmemberwangyanpeng17:07 12 Feb '09  
GeneralHi, Jerry.Wang PinmemberDuyThuong17:42 22 Oct '08  
GeneralRe: Hi, Jerry.Wang PinmemberJerry.Wang17:51 22 Oct '08  
GeneralRe: Hi, Jerry.Wang [modified] PinmemberDuyThuong23:04 23 Oct '08  
GeneralRe: Hi, Jerry.Wang Pinmemberyeskele18:06 13 Nov '08  
GeneralRe: Hi, Jerry.Wang PinmemberJerry.Wang15:37 16 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin 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