原理:

    假设用户在机器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. 开源一个CSV解析器(附设计过程 )

    在ExcelReport支持csv的开发过程中,需要一个NETStandard的csv解析器.在nuget上找了几个试用,但都不太适合. 于是,便有了:AxinLib.IO.CSV. 先看看怎么用: ...

  2. Syncfusion SfDataGrid 导出Excel

    var options = new ExcelExportingOptions { ExcelVersion = ExcelVersion.Excel2013, }; //不需要导出的字段 optio ...

  3. VM虚拟机下安装CentOS_6.5_x64

    在开始Linux的学习之前,我们必须要有一个实验环境.这里我选择了安装CentOS-6.5-x86_64的Minimal版本,大家也可以选择安装其他的Linux发行版.选择CentOS主要还是因为它比 ...

  4. java模式:建造者模式

    我发现很多源码很喜欢用这个模式,比如spring cloud,spring framework. 建造者模式(Builder)用以构建各种各样的对象,主要功能就是代替对象的构造函数,更加自由化. 举个 ...

  5. Houdini技术体系 基础管线(二) :Heightfiled与UE4的无缝导入以及对World Composition的支持

    Authored by TraceYang 前言    传统的制作做比较真实大世界3D关卡地形时,通常的采用的方式是把HeightMap和SplatMap(Layer Mask)导入到引擎的地形系统里 ...

  6. Ubuntu下创建新用户后,不能使用管理员用户下安装的Anaconda

    解决办法: 将管理员用户下Anaconda的安装环境添加到新用户下的环境变量里,具体操作: 系统切换到新用户下: vim .bashrc #添加Anaconda的环境变量 source .bashrc ...

  7. react文档demo实现输入展示搜索结果列表

    文档页面地址:https://doc.react-china.org/docs/thinking-in-react.html 该文档只给了具体实现思路,下面是我实现的代码. 初学react,如果有写的 ...

  8. Qt编写自定义控件8-动画按钮组控件

    前言 动画按钮组控件可以用来当做各种漂亮的导航条用,既可以设置成顶部底部+左侧右侧,还自带精美的滑动效果,还可以设置悬停滑动等各种颜色,原创作者雨田哥(QQ:3246214072),驰骋Qt控件界多年 ...

  9. ssh: connect to host xx.xx.xxx.xxx port 22: Connection refused

    执行 ssh root@47.94.142.215 报错 首先要开启ssh 系统偏好设置-共享 选上远程登陆 选上远程管理 检测openssh-server是否安装成功 ,安装成功的如下 ps -e ...

  10. 深度学习入门之Mnist

    参看Deep learning from scratch,学习到反向传播网络后,把网络调通了,但是训练后损失函数减小,准确率没有变化,和瞎猜一样,是为什么呢?只有在看看各层缺少什么,关键是我的参数和书 ...