第一步:给用户名一个对应的字段记录登陆状态,比如 online , 登陆后就为1, 同时还应增加记录用户活动时间,比如actionTime, 在基类(比如初始化Conn的类), 加上 update [用户表] set actionTime = getdate() where account = [用户名], 同时将长时间未活动的用户在线状态更新为0

第二步:登陆时通过online判断就可以了

/// <summary>
/// 单点登录帮助类
/// </summary>
public class SSOHelper
{
/// <summary>
/// 登录后执行
/// </summary>
/// <param name="UserID">用户标识</param>
public void LoginRegister(string UserID)
{
Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
if (hOnline != null)
{
IDictionaryEnumerator idE = hOnline.GetEnumerator();
string strKey = "";
while (idE.MoveNext())
{
if (idE.Value != null && idE.Value.ToString().Equals(UserID))
{
//already login
strKey = idE.Key.ToString();
hOnline[strKey] = "XXXXXX";
break;
}
}
}
else
{
hOnline = new Hashtable();
} hOnline[System.Web.HttpContext.Current.Session.SessionID] = UserID;
System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["Online"] = hOnline;
System.Web.HttpContext.Current.Application.UnLock();
} /// <summary>
/// 检查是否唯一登录
/// </summary>
/// <returns></returns>
public static bool CheckOnline()
{
Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
if (hOnline != null)
{
IDictionaryEnumerator idE = hOnline.GetEnumerator();
while (idE.MoveNext())
{
if (idE.Key != null && idE.Key.ToString().Equals(System.Web.HttpContext.Current.Session.SessionID))
{
//already login
if (idE.Value != null && "XXXXXX".Equals(idE.Value.ToString()))
{
hOnline.Remove(System.Web.HttpContext.Current.Session.SessionID);
System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["Online"] = hOnline;
System.Web.HttpContext.Current.Application.UnLock();
return false;
}
break;
}
}
}
return true;
} /// <summary>
/// Global文件的SessionEnd事件中增加此代码
/// </summary>
public static void GlobalSessionEnd()
{
Hashtable hOnline = (Hashtable)System.Web.HttpContext.Current.Application["Online"];
if (hOnline[System.Web.HttpContext.Current.Session.SessionID] != null)
{
hOnline.Remove(System.Web.HttpContext.Current.Session.SessionID);
System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["Online"] = hOnline;
System.Web.HttpContext.Current.Application.UnLock();
}
} }

在登录的时候调用一下LoginRegister方法

Global.asax中:

protected void Session_End(object sender, EventArgs e)
{
ltGameStore.Common.SSOHelper.GlobalSessionEnd();
}

剩下的就是在每次客户端对服务器有请求的时候验证当前会话ID是否被注销掉了(被其他用户挤掉)

我用的是一个继承Controller的基类,重写里面的OnAuhorization方法:

/// <summary>
/// 在进行授权时调用
/// </summary>
/// <param name="filterContext"></param>
protected override void OnAuthorization(AuthorizationContext filterContext)
{
//不能应用在子方法上
if (filterContext.IsChildAction)
return; //如果没有登录,则跳转到登录视图
if (WorkContext.Action != "login")
{
if (!TicketHelper.IsLogin())
{
filterContext.Result = new RedirectResult("/Account/login");
}
} if (!SSOHelper.CheckOnline())
{
filterContext.Result = PromptView("您的账号已在别处登录");
} //如果当前用户不是管理员
//if (WorkContext.AdminGid == 1)
//{
// if (WorkContext.IsHttpAjax)
// filterContext.Result = new ContentResult { Content = "404" };
// else
// filterContext.Result = new RedirectResult("/");
// return;
//}
}

注意,这样写的话会有个问题,每次客户端请求的SessionID都不一样,这样就无法校验了,搜了一下解决方法,在重写的Initialize方法(继承Controller的基类中)中不断的注册SessionId:

/// <summary>
/// 初始化调用构造函数后可能不可用的数据
/// </summary>
/// <param name="requestContext"></param>
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
Session["SessionId"] = Session.SessionID;
}

java.

我目前所知的方法可分为两种, 一是数据库来记录用户在线情况, 在登录把该用户数据库的标识字段赋值, 退出时让该字段复位. 二是通过全局的内存对象来记录用户情况,  以该用户的登录名如user做为key存入application中或是定义的一个全局的hashmap中, 退出删除全局对象中该user对应的信息, 据说还可用Cache全局对象,但相比.NET,java实现Cache不是太容易. 而这些对于用户的登录事件都能实时的做出处理, 但用户的退出显然多种多样, 乖乖点击注销可能性很小, 还得考虑断电,掉线等情况, 所以用户的退出事件程序是捕获不了的, 这是由session的机制决定的, 所以用户退出时,服务器想做到实时刷新是几乎是不可能的(除非用户点注销), 很多在线统计人数都不是实时的, 一般都是通过添加session监听器, 然后设置session失效时间, 时间到了则调用监听器的对应方法释放相关的数据, 如删除application中该用户的信息. 所以很可能会出现的一种情况是用户刚刚登录上系统, 然后掉线或其它原因, 然后该用户重新登录, 但系统提示该用户已经登录, 无法再次登录. 只能等到原来的session失效, 遇到这种情况想必是很郁闷. 这种情况是无法解决的, 就其根本还是因为用户的退出是无法确定的, 服务器无法区分用户的真在线还是假在线. 既然这样可以像QQ一样以顶号的方式来处理, 就是用户登录时判断application中是否有该用户信息存在, 有则替换, 无则写入, 这样同一个账号的话, 先登录的会被后登录的踢出, 这就无需理会先登录的用户是真在线还是假在线, 达到了实时的效果。不过我们项目不让这么用, 目办法只能用session监听了。Servlet里面一共有八个监听, 其中有四个是session的监听接口与之关联的两个session事件, 
这四个接口分别是: 
HttpSessionAttributeListener and HttpSessionBindingEvent
HttpSessionBindingListener and HttpSessionBindingEvent
HttpSessionListener and HttpSessionEvent
HttpSessionActivationListener and HttpSessionEvent

HttpSessionAttributeListener: 用来监听session中的属性添加, 替换和删除, 只需创建一个类来实现HttpSessionAttributeListener接口, 然后在web.xml配个listener属性,其中litener-class是这个类的路径. 该类会实现HttpSessionAttributeListener的三个方法. 分别对应session中的属性添加, 替换和删除. 该类无需我们实例化使用, 因为servlet容器会创建该类的一个实例, 并是单例. 所以访问该系统的所有用户对session属性的操作都会被HttpSessionAttributeListener监听到. HttpSessionBindingEvent事件的触发对象是任何object的实例, 因为session的setAttribute方法中可以存放任何object的实例。HttpSessionBindingListener: 创建实现HttpSessionBindingListener接口的类, 不需在web.xml中配置, 该类会实现HttpSessionBindingListener的两个方法valueBound()和valueUnbound(), 该类需要实例化使用, 将该类实例对象放入session后会马上触发valueBound()方法, 从session中remove掉该实例时或session超时会马上触发valueUnbound(), 很显然每个servlet都会创建一个该类的对象,所以多用户并发调用时它们都是相互独立的, 而且可以创建多个实现HttpSessionBindingListener接口的类, 效果依然一样。
HttpSessionBindingEvent事件的触发对象是该类的实例本身(有点绕口),

举例
public class SessionListener implements HttpSessionBindingListener....
SessionListener sessionListener = new SessionListener();

//下面这句即是触发HttpSessionBindingEvent事件, 而触发对象正是sessionListener, 监听器的实例本身
request.getSession().setAttribute(request.getSession().getId(), sessionListener);

HttpSessionListener:监听session的创建和释放, 需在web.xml中配置, 重写sessionCreated()和sessionDestroyed()方法, 它同样是容器创建的单列对象, 可以监听所有用户的session创建, 适合来做统计, 得注意的一点是, 在浏览器访问服务器时, session的会话就创建了, 而session释放后才会调用sessionDestroyed()方法, 所以不能在sessionDestroyed()内做session清理工作, 因为已经无法获得session了。

HttpSessionActivationListener:当session在分布式环境中跨JVM时,实现该接口的对象得到通知, 需实行的方法sessionDidActivate()和sessionWillPassivate(),  Activate与Passivate是用于置换对象的动作,当session对象为了资源利用或负载平衡等原因而必须暂时储存至硬盘或其它储存器时(透过对象序列化),所作的动作称之为Passivate,而硬盘或储存器上的session对象重新加载JVM时所采的动作称之为Activate,所以容易理解的,sessionDidActivate()与 sessionWillPassivate()分别于Activeate后与将Passivate前呼叫。

这四个都与session有关,但能做到验证登录的只有HttpSessionBindingListener and HttpSessionListener,无疑使用前者更合适些。

.net 账号异地登录的更多相关文章

  1. shiro解决一个账号异地登录的问题

    如下,找到session中的信息删除即可,按照这个方式试了下.基本可用 在多台服务器部署时,前提必须实现session共享. /** * 登录认证 * @param token * @return * ...

  2. 运用session来控制用户的异地登录被挤下线情况

    在用QQ的过程中我们如果你的账号在另外一台手机上面登录,这是腾讯后台会提醒你异地登录,可能你的账号被盗了,然后你手机上得QQ就会被退出登录,这个时候你就需要重新登录修改密码,以确保账号的安全.那这种被 ...

  3. Windows 服务器开通防火墙后,IISFTP和Serv U开通的FTP账号不能登录

    应广大服务器客户要求一至反应Windows 服务器开通防火墙后,IISFTP和Serv U开通的FTP账号不能登录,出现列表超时的情况,特提供以下解决方案: 1. IIS FTP用户解决方法: 在防火 ...

  4. 背水一战 Windows 10 (84) - 用户和账号: 微软账号的登录和注销

    [源码下载] 背水一战 Windows 10 (84) - 用户和账号: 微软账号的登录和注销 作者:webabcd 介绍背水一战 Windows 10 之 用户和账号 微软账号的登录和注销 示例演示 ...

  5. mongodb副本集加分片集群安全认证使用账号密码登录

    mongodb副本集加分片集群搭建网上资料有很多.粘贴一个写的比较好的.副本集加分片搭建 对于搭建好的mongodb副本集加分片集群,为了安全,启动安全认证,使用账号密码登录. 默认的mongodb是 ...

  6. Android利用融云做异地登录提醒

    在RongCloudEvent下找到onChanged方法 @Override public void onChanged(ConnectionStatus connectionStatus) { s ...

  7. shiro整合shiro多验证登录(账号密码登录和使用手机验证码登录)

    1. 首先新建一个shiroConfig  shiro的配置类,代码如下: @Configuration是标识这个类是一个配置文件,在启动时会加载这个类里面的内容,这个配置文件的位置的一定一定一定不能 ...

  8. linux pptpd账号同时登录的问题

    最近搞了个云主机搭建个VPN服务器给自己用, 特别是在公共场所的wifi上网时, 很多APP, 或者网站是没有https的, 所以为了保证信息(主要是账号密码)的安全, 搭个私有vpn还是很有必要的. ...

  9. IIS绑定Active Directory账号自动登录网站的方法

    满足使用Request.ServerVariables["REMOTE_USER"]的条件: 1.IIS配置网站的目录安全性取消“启用匿名访问(&A)” 2.启用 “集成 ...

随机推荐

  1. jquery限制文本框只能输入金额

    $("#batch_diff_percent").keyup(function () { var reg = $(this).val().match(/\d+\.?\d{0,2}/ ...

  2. 【单页应用之通信机制】view之间应该如何通信

    前言 在单页应用中,view与view之间的通信机制一直是一个重点,因为单页应用的所有操作以及状态管理全部发生在一个页面上 没有很好的组织的话很容易就乱了,就算表面上看起来没有问题,事实上会有各种隐忧 ...

  3. iOS 开源项目

    在 Github 上 Star 太多了,有时候很难找到自己想要的开源库,所以在此记录下来.便于自己开发使用,也顺便分享给大家. 动画 awesome-ios-animation收集了iOS平台下比较主 ...

  4. HTML5学习之 开发工具

    Notepad++.Editplus 是常用的开发编辑器.这些在Window系统下,比较容易找到,但是在MAC系统下,有的是收费的,有的是不支持.我开发的时候,用的是TextWrangler,如图: ...

  5. arcgis arcengine Using environment settings

    In this topic About using environment settings Environment settings summary table About using enviro ...

  6. TouchDevelop [Mobile App]

    TouchDevelop是一个全新的Windows Phone软件开发环境,是第一个可以使用手机编程的应用. 所用语言看上去有点像BASIC,也有Scratch和AppInventor那样的色块拖拽环 ...

  7. 使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First

    [前言] 如果是Code First老鸟或者对Entity Framework不感兴趣,就不用浪费时间往下看了. 记得09年第一次接触ORM————Linq2Sql,从此对她的爱便一发不可收拾,一年后 ...

  8. [DOM Event Learning] Section 1 DOM Event 处理器绑定的几种方法

    [DOM Event Learning] Section 1 DOM Event处理器绑定的几种方法   网页中经常需要处理各种事件,通常的做法是绑定listener对事件进行监听,当事件发生后进行一 ...

  9. Android Studio 恢复小窗口停靠模式(Docked Mode)

    安卓studio在使用小窗口时,如果我们点击取消了窗口的docked mode模式,窗口就会变成,你一旦触发窗口以外的区域,窗口就会龟缩回去.此时,如果你想要恢复回原来的docked mode的话,具 ...

  10. 开篇:软件项目的整个流程 - IT软件人员学习系列文章

    这段时间闲来无事,就在总结以前的项目经验,然后写成博客的形式以进行记录.本文就对<IT软件人员学习系列文章>做个开篇吧. 对于IT软件的开发来说,无外乎B/S.C/S和Android.iO ...