Navigation

Search

Categories

On this page

Preventing Duplicate Logins

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 112
This Year: 50
This Month: 0
This Week: 0
Comments: 0

Sign In

 Monday, June 18, 2007
Monday, June 18, 2007 11:21:48 AM (Eastern Standard Time, UTC-05:00) (  |  )

I recently had to put into place a method that prevented more than one user from logging into our company web site under the same login ID. With the help of a friend, this is what we came up with. 

Basically, each time a user logs in, the user's UserID and sessionID are stored in a database table at login.  Each time the user visits a page in the site, the user's session ID is matched against what is stored in the database.  If the sessionIDs do not match, then the user is logged out and redirected to a page that says something like "duplicate login detected.  you're a cheating bum. etc."

A typical scenario would work like this:

User A logs into the site and the sessionID is recorded into the dbase. She browses from page and page within the site and on each page her sessionID is verified against what's stored in the database.

User B then logs into the site using User A's ID and password. The sessionID information stored in the database for User A is overwritten by User B. When user A tries to browse to another page, she receives a message stating that someone has logged into the site using her ID.  User A can log back in, but then User B will receive the duplicate login message and round and round they go.

Here's the code for it.

This stored procedure is called on the login page. If the user's userID is not already in the datbase, then it is inserted as a new record. Otherwise, the existing record is updated with the new session ID.

CREATE Procedure sp_LoginStatusCheck
@UserID as Int,
@SessionID as nvarchar(100)


AS
    IF (SELECT COUNT(UserID)
FROM TLoginStatus
WHERE UserID = @UserID) = 0
        
BEGIN
INSERT INTO TLoginStatus(UserID, SessionID) Values (@UserID, @SessionID)
    
END
ELSE
         UPDATE TLoginStatus
         SET SessionID = @SessionID
         WHERE UserID = @UserID
GO

Call sp_LoginStatusCheck in the login page.

Sub AddSessionCheck(ByVal UserID As Integer)
'Due to some bizarre requirement that there must be some value assigned to a Session variable not to lose
'the value for SessionID, I created a random session variable and value            
Session("BA") = "BA"
            
            
Dim myConnection As SqlConnection
Dim cmd As SqlCommand
            
myConnection = New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
cmd = New SqlCommand("sp_LoginStatusCheck", myConnection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("@UserID", SqlDbType.Int, 4).Value = UserID
cmd.Parameters.Add("@SessionID", SqlDbType.NVarChar, 100).Value = Session.SessionID
                        
Try
myConnection.Open()
cmd.ExecuteNonQuery()
Finally
myConnection.Close()
End Try

End Sub


On each page that I Want to check for a duplicate login, I would first get the userID value which is stored in a cookie value in the Page_Load function. 

<%@ Page Language="VB" Inherits="MyBaseClass" src="~/classes/MyBaseClass.vb" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQLClient" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
Sub Page_Load()
If Not IsPostBack Then
Dim strUserID As String
If Not IsNothing(Request.Cookies("BA")) Then
strUserID = Request.Cookies("BA")("UserID").ToString()
lblUserID.Value = strUserID
End If


'Call CheckLoginStatus
    CheckLogin(strUserID)
    
End If
End Sub
</script>

I created a new class called MyBaseClass with a sub called CheckLogin that accepts UserID as a parameter. This gets called on every page that I check.

Imports Microsoft.VisualBasic
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web.Configuration
Imports System.Web.HttpContext

Public Class MyBaseClass
Inherits System.Web.UI.Page

Public Shared Sub CheckLogin(ByVal UserID As Integer)

'This entire section is the duplicate login prevention section
System.Web.HttpContext.Current.Session("Spice") = "Ginger"
Dim strSessionID = System.Web.HttpContext.Current.Session.SessionID
Dim strLoginStatus As String

Dim MyConnection As SqlConnection
Dim Cmd As SqlCommand

MyConnection = New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
Cmd = New SqlCommand("sp_LoginStatusCheck2", MyConnection)
Cmd.CommandType = CommandType.StoredProcedure
Cmd.Parameters.Add("@UserID", SqlDbType.Int, 4).Value = UserID
Cmd.Parameters.Add("@SessionID", SqlDbType.NVarChar, 100).Value = strSessionID
Cmd.Parameters.Add("@LoginStatus", SqlDbType.Bit).Direction = ParameterDirection.Output

Try
MyConnection.Open()
Cmd.ExecuteNonQuery()
strLoginStatus = Cmd.Parameters(2).Value
'System.Web.HttpContext.Current.Response.Write(strLoginStatus)
Finally
MyConnection.Close()
End Try

If strLoginStatus = "False" Then
System.Web.HttpContext.Current.Response.Redirect("/duplicate.login.aspx")
End If

End Sub

End Class

Here's the code for the stored procedure sp_LoginStatusCheck2

CREATE Procedure sp_LoginStatusCheck2
@UserID as Int,
@SessionID as nvarchar(100),
@LoginStatus as Bit OUTPUT

--We don't want to check the LoginStatus of enterprise level accounts UserID 884, UserID 7996
AS
IF @UserID=884
    SET @LoginStatus = 1
ELSE IF @UserID=7996 
    SET @LoginStatus = 1
ELSE    

    IF (SELECT COUNT(*) FROM TLoginStatus WHERE UserID = @UserID AND SessionID = @SessionID) > 0
        SET @LoginStatus = 1
    ELSE
        SET @LoginStatus = 0
GO