I’ve been working on a subscription site, logins are powered by the ASP.net membership provider system.
Now I want to stop people sharing their logins and avoiding paying for a subscription. We don’t really want multiple logins from the same username.
After a lot of Googling I came up with an almost suitable solution:
http://www.eggheadcafe.com/articles/20030418.asp
The only problem for me is that this solution stops a new login. This means that if a user logs in, closes the browser, and then logs in again, they are denied a login for the next twenty minutes (or however long the session timeout is set to).
So I switched things around, and actually ended up with a slightly simpler solution.
In my asp:Login control’s LoggedOn event I have the following:
protected void LoginMain_LoggedIn(object sender, EventArgs e)
{
System.Web.UI.WebControls.Login senderLogin = sender as System.Web.UI.WebControls.Login;
string key = senderLogin.UserName + senderLogin.Password;
TimeSpan TimeOut = new TimeSpan(0, 0, HttpContext.Current.Session.Timeout, 0, 0);
HttpContext.Current.Cache.Insert(key,
Session.SessionID,
null,
DateTime.MaxValue,
TimeOut,
System.Web.Caching.CacheItemPriority.NotRemovable,
null);
Session["username"] = key;
}
We concatonate the username and password as before and use this as the key for a cache item. The cache item value though is set to the just logged in users SessionID. We then add the key to a session variable.
In global.asax we have:
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
if (Session["username"] != null)
{
string cacheKey = Session["username"].ToString();
if ((string)HttpContext.Current.Cache[cacheKey] != Session.SessionID)
{
FormsAuthentication.SignOut();
Session.Abandon();
Response.Redirect("/errors/DuplicateLogin.aspx");
}
string user = (string)HttpContext.Current.Cache[cacheKey];
}
}
}
This will fire for every request. If the username session variable exists then the SessionID is taken from the cache and compared to the current SessionID. If they don’t match then the user is kicked to an error page after being logged out and Session.Abandoned.
This means that a second user logging in will change the cached SessionID and login fine, whilst the original user will be logged out.
The error message explains what has happened and provides support for what to do. Which is of course either, stop cheating me out of cash, or let us know if you think your account is compromised.