ASP.Net同时只允许一个用户登录问题求解

雨天里的蘑菇芽 2014-10-13 04:13:21
大家好,我现在想要在B/S结构的项目中实现单点登录的功能,即一个登录帐号只能同时一台机器使用,比如帐号admin/admin在192.168.1.123机器上登录且Session是活跃状态时,帐号admin/admin就不能在其他机器上登录,目前我实现的Code如下:
1. 在登录事件中:

/// <summary>
/// 用户点击登陆按钮进行登录操作。
/// </summary>
protected void btnLogin_Click(object sender, EventArgs e)
{
var userInfo = PrivilegeManager.GetUserInfo(strLoginID, strLoginPwd);
if (userInfo != null)
{
var iPAddresses = Dns.Resolve(Dns.GetHostName()).AddressList;
var dateTimeNow = DateTime.Now;
if (null != iPAddresses && iPAddresses.Length > 0)
{
//1表明当前帐号已经被占用,0为否
if (string.Equals("1", userInfo.IsUsed, StringComparison.InvariantCultureIgnoreCase) && userInfo.LastLoginTime.HasValue)
{
var diffTime = dateTimeNow - userInfo.LastLoginTime.Value;
var sessionTimeOut = HttpContext.Current.Session.Timeout;
if (diffTime.TotalMinutes < sessionTimeOut && !string.Equals(iPAddresses[0].ToString(), userInfo.LoginIPAddress, StringComparison.InvariantCultureIgnoreCase))
{
Alert.Show("对不起,您当前帐户已经被其他人使用了,请您更换其它帐号后再尝试登陆!", "登陆失败", MessageBoxIcon.Warning);
return;
}
}

//更新P_USERACCOUNT表的帐户信息为占用状态,登录地址为当前机器的IP
PrivilegeManager.UpdateUserAccountStatus("1", userInfo.AccountGuid, dateTimeNow, iPAddresses[0].ToString());

Session[ConstValue.SESSION_USER_INFO] = userInfo;
Response.Redirect("/default.aspx");
}
}
else
{
Alert.Show("用户名或密码错误,请重试!");
this.txtLoginID.Focus();
return;
}
}

2. 在Global.asax文件中:

protected void Application_EndRequest(object sender, EventArgs e)
{
var iPAddresses = Dns.Resolve(Dns.GetHostName()).AddressList;
if (null != iPAddresses && iPAddresses.Length > 0)
{
var ipAddress = iPAddresses[0].ToString();
var userAccountGuid = PrivilegeManager.GetLoginAccountGuidByIP(ipAddress);
if (!string.IsNullOrEmpty(userAccountGuid))
{
//如果收到了请求,则说明该帐号是在线状态,则更改最后登陆时间为当前时间,登陆IP为当前机器IP
PrivilegeManager.UpdateUserAccountStatus("1", userAccountGuid, DateTime.Now, ipAddress);
}
}
}

3. 数据库中的表设计如下:


问题是 当帐号admin/admin在一机器上属于登录状态且Session没过时的情况下,另外一个用户在另外一台机器上也使用admin/admin登录,则会把之前的用户强制下线。如果不这样写,就处理不了当用户使用admin/admin在一台机器上登录后意外关闭了浏览器且Session还没到期,则其他用户想在他的机器上使用admin/admin登录也登录不了。
求大神帮忙分析并提出解决方案,感激不尽!!! :)
...全文
890 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
liu7537 2016-12-21
  • 打赏
  • 举报
回复
5楼说的有道理,就是后登陆用户踢掉先登录用户,就这么一个逻辑就行,其他的都不需要考虑。
CodeMonkey丶 2015-08-13
  • 打赏
  • 举报
回复
确定不是单态登陆?..单点登录概念不是这样的.............
三楼の郎 2014-10-13
  • 打赏
  • 举报
回复
提两个思路供你参考 1、用数据库保存SessionState,.net里面Session的存储方式有三种Inproc、StateServer和数据库,用数据库的话所有Session变量会保存到数据库的某个表里面,其它用户登录的时候只需要检查一下这个表里面是不是有某个用户的记录就行了,如果有Session没到期意外关闭的情况,等到Session超时时间到系统会自动清理,清理完成就可以登录了,session有效期默认可以保持20分钟(没有活动的情况下),等20分钟也不算长。 2、顶楼那个表里面加两个字段SessionID 和 LastUpdateTime 用来记录当前登录用户的SessionID和最后一次请求时间,每次向服务器请求页面的时候都需要更新对应的LastUpdateTime字段内容为当前时间,其它用户登录的时候检查SessionID字段是否有内容和当前需要登录的用户的SessionID字段是否相同,如果有内容且不相同就再去检查LastUpdateTime时间有没有超时,自己定一个超时时间,超过了规定时间没有动作就当他已经退了
wjq 2014-10-13
  • 打赏
  • 举报
回复
session有效期默认可以保持20分钟(没有活动的情况下)。如果你要做到完美的单点登录,那么在每个页面(或者主模板页)加上一段ajax代码以非常小的时间间隔去访问后台,并记录当前用户+当前时间(建议放在一个内存静态变量中,而非数据库)。 这样登录的时候可以不要检查session,而改为检查这个时间(大于你的时间间隔)就可以认为该用户不活跃了。 代价就是可能有性能问题。所以可以考虑将时间间隔设置成1-5分钟左右(视你自己项目情况而定)这样即便有人不小心关了浏览器,那么其他人登录等待的时间也不用太长。
qzyf1992 2014-10-13
  • 打赏
  • 举报
回复
引用 9 楼 yuwenge 的回复:
[quote=引用 6 楼 diaodiaop 的回复:] [quote=引用 4 楼 qzyf1992 的回复:] 你直接在数据库里定义一张存用户状态表 某用户登录如果检查用户名密码正确 还必须检查这种表 如果该用户名对着的信息为1代表在线不允许登录,如果为0 说明没人登录允许登录 然后给session赋值把这个信息置为1。实时的监视iis进程里的session值一旦被销毁。那么把这个1又置为0.或者你把session信息存到db里
你用什么技术监听session值是否过期?
引用 5 楼 yuwenge 的回复:
单点登录只能是后登陆用户踢掉先登录用户。 至于为什么,这是一个简单的生活逻辑,自己慢慢想。
LZ的问题是单用户 而不是单点登陆 而且
引用
单点登录只能是后登陆用户踢掉先登录用户
单点登陆不是登陆一次访问多个系统吗[/quote] 我说的就是单用户。 如果用户在A处登陆后未退出,而且忘记这件事情了,那么是不是以后永远也登不上去了?[/quote] session会过期的。。。
epui2008 2014-10-13
  • 打赏
  • 举报
回复
数据库加标示 登录后更改标示,根据标示 判断是否允许后面的人登录
rayyu1989 2014-10-13
  • 打赏
  • 举报
回复
增加用户字段state,登录时候把登录时间戳写入state(同时写入cache),保存的用户凭据里存储state, 页面载入时候比对凭据state是否和cache中的state一致(无cache取数据库),如果一致为最后登录的用户,如果不一致 说明在其他pc登录了
卧_槽 2014-10-13
  • 打赏
  • 举报
回复
引用 6 楼 diaodiaop 的回复:
[quote=引用 4 楼 qzyf1992 的回复:] 你直接在数据库里定义一张存用户状态表 某用户登录如果检查用户名密码正确 还必须检查这种表 如果该用户名对着的信息为1代表在线不允许登录,如果为0 说明没人登录允许登录 然后给session赋值把这个信息置为1。实时的监视iis进程里的session值一旦被销毁。那么把这个1又置为0.或者你把session信息存到db里
你用什么技术监听session值是否过期?
引用 5 楼 yuwenge 的回复:
单点登录只能是后登陆用户踢掉先登录用户。 至于为什么,这是一个简单的生活逻辑,自己慢慢想。
LZ的问题是单用户 而不是单点登陆 而且
引用
单点登录只能是后登陆用户踢掉先登录用户
单点登陆不是登陆一次访问多个系统吗[/quote] 我说的就是单用户。 如果用户在A处登陆后未退出,而且忘记这件事情了,那么是不是以后永远也登不上去了?
  • 打赏
  • 举报
回复
LS说的差不多了 你这需求 肯定不是用session来控制实现的。 而且,单点登录,是指 登录一次后,可以直接进入不同的系统中 类似于你登录xunlei.com后,可以直接进入lixian.xunlei.com。 迅雷看看首页和迅雷离线空间完全是两个的东西。
qzyf1992 2014-10-13
  • 打赏
  • 举报
回复
引用 6 楼 diaodiaop 的回复:
[quote=引用 4 楼 qzyf1992 的回复:] 你直接在数据库里定义一张存用户状态表 某用户登录如果检查用户名密码正确 还必须检查这种表 如果该用户名对着的信息为1代表在线不允许登录,如果为0 说明没人登录允许登录 然后给session赋值把这个信息置为1。实时的监视iis进程里的session值一旦被销毁。那么把这个1又置为0.或者你把session信息存到db里
你用什么技术监听session值是否过期?
引用 5 楼 yuwenge 的回复:
单点登录只能是后登陆用户踢掉先登录用户。 至于为什么,这是一个简单的生活逻辑,自己慢慢想。
LZ的问题是单用户 而不是单点登陆 而且
引用
单点登录只能是后登陆用户踢掉先登录用户
单点登陆不是登陆一次访问多个系统吗[/quote] Quartz.Net session完全可以存数据库里 数据库触发器也可以。
by_封爱 2014-10-13
  • 打赏
  • 举报
回复
引用 4 楼 qzyf1992 的回复:
你直接在数据库里定义一张存用户状态表 某用户登录如果检查用户名密码正确 还必须检查这种表 如果该用户名对着的信息为1代表在线不允许登录,如果为0 说明没人登录允许登录 然后给session赋值把这个信息置为1。实时的监视iis进程里的session值一旦被销毁。那么把这个1又置为0.或者你把session信息存到db里
你用什么技术监听session值是否过期?
引用 5 楼 yuwenge 的回复:
单点登录只能是后登陆用户踢掉先登录用户。 至于为什么,这是一个简单的生活逻辑,自己慢慢想。
LZ的问题是单用户 而不是单点登陆 而且
引用
单点登录只能是后登陆用户踢掉先登录用户
单点登陆不是登陆一次访问多个系统吗
卧_槽 2014-10-13
  • 打赏
  • 举报
回复
单点登录只能是后登陆用户踢掉先登录用户。 至于为什么,这是一个简单的生活逻辑,自己慢慢想。
qzyf1992 2014-10-13
  • 打赏
  • 举报
回复
你直接在数据库里定义一张存用户状态表 某用户登录如果检查用户名密码正确 还必须检查这种表 如果该用户名对着的信息为1代表在线不允许登录,如果为0 说明没人登录允许登录 然后给session赋值把这个信息置为1。实时的监视iis进程里的session值一旦被销毁。那么把这个1又置为0.或者你把session信息存到db里
by_封爱 2014-10-13
  • 打赏
  • 举报
回复
引用 2 楼 sun_shine_jin 的回复:
谢谢您的回复,您说的很有道理,可是我觉得您这种方法还是有些缺陷的,因为一更新就清空了所有用户的状态,这个可能不符合我的需求哦!不过很感激您的回复,希望有更多的高手可以指点!
清空为什么不行? 情况马上就又更新成1了... -------------------------------------------------------------------------------------------------------- 为了限制使用用户最多30个在线我曾经在一个系统中这样做过.. 用户登录之后 就settimeout(3s)+ajax执行一个proc参数(uid用户编码) proc大概是这样的(时间久了有一些忘记了) 操作表 uid lasttime 2个字段 删除5秒之前的数据 先判断当前表是否有uid这个用户..如果有 那么更新lasttime 如果没有 insert table values(uid,getdate()) ------------------------------------------------------------------------------------------ 代码就这样了3s就会访问这个存储过程(当然是很多人都访问) 为什么我说这个代码可以实现控制在线人数以及但用户登录呢. 首先我们来说 如果2个人登陆 数据中只有2个.lasttime不断更新 ... 如果你想判断登陆不允许重复 那么查询是否有这个用户即可. 如果判断在线人数控制,.count即可 假设 其中有一个人 意外掉线(不管是任何) 那么A在执行存储过程的时候 由于第一个操作(删除) 会把这个人的记录删除..所以 在线人数 只有1 下一次在登陆 他执行的是 insert 然后才是update 所以 我认为我这个完全能实现你目前的功能.. !
  • 打赏
  • 举报
回复
引用 1 楼 diaodiaop 的回复:
使用session这东西来限制用户根本不靠谱的.. 强制关机 断电 任务管理器结束IE 这些你是捕获不到的 因为目前的web没有"实时"这个东西.所以 如果你真的想实现<单用户>,你至少得虚拟的实现<实时> 比如settimeout.+ajax 或者推送的框架 或者websocket来弄. 假设实现了<实时>无非就是一直更新user表的在线状态.后面的人登陆的时候判断状态 当然这样会产生一样的问题 就是关闭的时候 在线状态还是在线. 所以"直更新user表的在线状态"这个动作可以先清空所有用户的状态..然后在更新当前用户的状态. 当然这样的话性能不好以及有死角..比如某一秒可能会出现失败. 这只是解决方案最不好的一种..最起码的 至少实现了..你所谓的那个东西 应该不行的
谢谢您的回复,您说的很有道理,可是我觉得您这种方法还是有些缺陷的,因为一更新就清空了所有用户的状态,这个可能不符合我的需求哦!不过很感激您的回复,希望有更多的高手可以指点!
by_封爱 2014-10-13
  • 打赏
  • 举报
回复
使用session这东西来限制用户根本不靠谱的.. 强制关机 断电 任务管理器结束IE 这些你是捕获不到的 因为目前的web没有"实时"这个东西.所以 如果你真的想实现<单用户>,你至少得虚拟的实现<实时> 比如settimeout.+ajax 或者推送的框架 或者websocket来弄. 假设实现了<实时>无非就是一直更新user表的在线状态.后面的人登陆的时候判断状态 当然这样会产生一样的问题 就是关闭的时候 在线状态还是在线. 所以"直更新user表的在线状态"这个动作可以先清空所有用户的状态..然后在更新当前用户的状态. 当然这样的话性能不好以及有死角..比如某一秒可能会出现失败. 这只是解决方案最不好的一种..最起码的 至少实现了..你所谓的那个东西 应该不行的

62,244

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧