原理:

    假设用户在机器A登陆后,

    这时用户再次在机器B登陆,会以当前会话的SessionID作为,用户id作为,插入dictionary集合中,集合再保存在application(保存在服务器的全局变量,多用户可以共享)变量中,

同时判断集合中是否有其他值,这里A机器已经登陆,所以会有A机器登陆的键值对,将A机器的键对应值修改为“_offline_”,以表示强制下线,

    A机器的页面通过js轮询去查询dictionary集合,发现中SessionID键对应的值被修改为“_offline_”,从而注销登陆,并提示被迫下线。

1、global中的代码:

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
} //保证同一次会话的SessionID不变
protected void Session_Start(object sender, EventArgs e)
{ } protected void Session_End(object sender, EventArgs e)
{
Hashtable hOnline = (Hashtable)Application["Online"];
if (hOnline != null)
{
if (hOnline[Session.SessionID] != null)
{
hOnline.Remove(Session.SessionID);
Application.Lock();
Application["Online"] = hOnline;
Application.UnLock();
}
}
}
}
注:保证同一次会话的SessionID不变,这点很重要

2、用户登陆代码:
.....

HttpContext httpContext = System.Web.HttpContext.Current;
var userOnline =
(Dictionary<string,string>)httpContext.Application["Online"];
if (userOnline != null)
{

            IDictionaryEnumerator enumerator = userOnline.GetEnumerator();
            while (enumerator.MoveNext())
            {
              if (enumerator.Value != null && enumerator.Value.ToString().Equals(userID.ToString()))
              {
                userOnline[enumerator.Key.ToString()] = "_offline_";
                break;
              }
            }

}

else
{
userOnline = new Hashtable();
}
userOnline[Session.SessionID] = userID.ToString();
httpContext.Application.Lock();
httpContext.Application["Online"] = userOnline;
httpContext.Application.UnLock(); ......

4、页面轮询(可以在母版页,公共页)

前台js用的easyui

$(document).ready(function () {
//定时检测是否被强制下线
setInterval(function () {
CheckIsForcedLogout();
}, 5000);
}); //检测是否被强制下线
function CheckIsForcedLogout() {
$.ajax({
url: "/Home/CheckIsForcedLogout",
type: "POST",
dataType: "json",
success: function (msg) {
if (msg.OperateResult == "Success") {
$.messager.alert('', msg.OperateData, 'error', function () {
window.location.href = "/Account/Login";
});
}
},
error: function (ex) { }
});
}
 [HttpPost]
public JsonResult CheckIsForcedLogout()
{
try
{
HttpContext httpContext = System.Web.HttpContext.Current;
Hashtable userOnline = (Hashtable)httpContext.Application["Online"];if (userOnline != null)
{
if (userOnline.ContainsKey(httpContext.Session.SessionID))
{
var value=userOnline[httpContext.Session.SessionID];
//判断当前session保存的值是否为被注销值
if (value != null && "_offline_".Equals(value))
{
//验证被注销则清空session
userOnline.Remove(httpContext.Session.SessionID);
httpContext.Application.Lock();
httpContext.Application["online"] = userOnline;
httpContext.Application.UnLock(); string msg = "下线通知:当前账号另一地点登录, 您被迫下线。若非本人操作,您的登录密码很可能已经泄露,请及时改密。"; //登出,清除cookie
FormsAuthentication.SignOut(); return Json(new { OperateResult = "Success", OperateData = msg }, JsonRequestBehavior.AllowGet);
}
}
}
return Json(new { OperateResult ="Failed" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { OperateResult = "Failed" }, JsonRequestBehavior.AllowGet);
}
}

这里登陆后,每5秒轮询服务器(获取最后登陆时间、ip是从redis缓存读取,所以轮询没有访问数据库),然后不访问数据库,但是数据量大的话,服务器压力也是挺大的,暂时没有更好的解决方案。

asp.net mvc 简单实现一个账号只能在一个地方登录的更多相关文章

  1. java 实现 一个账号只能在一个地方登陆,其他地方被下线

    其实方法有很多的,我这献丑了. 使用理解java 四大作用域. 思路:理解java 四大作用域的关键. 第一个地方登陆: 1.得到请求的SessionId 和 登陆的 用户名 2.把SessionId ...

  2. Asp.net 实现只能允许一个账号同时只能在一个地方登录

    先上帮助类: /// <summary> /// 单点登录帮助类 /// </summary> public class SSOHelper { /// <summary ...

  3. shiro 实现单用户登录,一个用户同一时刻只能在一个地方登录

    我这里 shiro 并没有集成 springMVC,直接使用 ini 配置文件. shiro.ini [main] # Objects and their properties are defined ...

  4. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  5. ASP.NET MVC 5 - 添加一个模型

    在本节中,您将添加一些类,这些类用于管理数据库中的电影.这些类是ASP.NET MVC 应用程序中的"模型(Model)". 您将使用.NET Framework 数据访问技术En ...

  6. ASP.NET MVC 简单介绍①

    ASP.NET  MVC 简单介绍① 只做了重要描述,内容出自菜鸟教程网站内容. 目录 1布局 2HTML 帮助器 3.Razor 语法 4.添加样式 5.Layout 6. Controllers ...

  7. ASP.NET MVC 简单分页代码

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  8. [转]ASP.NET MVC 5 - 添加一个模型

    在本节中,您将添加一些类,这些类用于管理数据库中的电影.这些类是ASP.NET MVC 应用程序中的"模型(Model)". 您将使用.NET Framework 数据访问技术En ...

  9. Asp.net MVC 简单分页 自做简单分页

    Asp.net MVC 简单分页:   public static string Pager(int page,int pageSize,int total)         {           ...

随机推荐

  1. Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信

    当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...

  2. SVN:This client is too old to work with working copy…解决的方法

    解决svn:This client is too old问题 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbXlmbXlmbXlmbXlm/font/5a ...

  3. 游戏行业DDoS攻击解决方案

    行业综述 根据全球游戏和全球移动互联网行业第三方分析机构Newzoo的数据显示:2017年上半年,中国以275亿美元的游戏市场收入超过美国和日本,成为全球榜首. 游戏行业的快速发展.高额的攻击利润.日 ...

  4. 当使用 SelfHost 的 OWIN 承载 SignalR 时,重启 OWIN 后,SignalR 不能正常工作

    需要在初始化时,重新对 Resolver 赋值一个新的实例: public class Startup { public void Configuration(IAppBuilder app) { v ...

  5. Python Every Class Needs a __repr__

    一.思考 当我们在Python中定义一个类的时候,如果我们通过print打印这个类的实例化对象,或者我们直接输入这个类实例化对象会返回怎么样的结果,如下代码: >>> class P ...

  6. 从yield 到yield from再到python协程

    yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...

  7. Atitit 关于共享经济之共享男女朋友的创业计划

    Atitit 关于共享经济之共享男女朋友的创业计划 1. 共享经济的历史与趋势 1 1.1. 共享经济三大特征=产能过剩+共享平台+人人参与. 1 1.2. 共享经济是个大趋势,使用权渐渐的取代所有权 ...

  8. linux epoll学习

    #include <sys/time.h> /* For portability */ #include <sys/select.h> int select(int nfds, ...

  9. easyUI的汇总列,在前端生成

    1.easyUI初始化,启用汇总列,showFooter:true 2.后台json有默认的footer的值 {"total":28,"rows":[ {&qu ...

  10. C语言 · 数的划分

    算法训练 数的划分   时间限制:1.0s   内存限制:256.0MB        锦囊1 使用动态规划. 锦囊2 用F[i,j,k]表示将i划分成j份,最后一份为k的方案数,则F[i,j,k]= ...