背景:

先上个图,看一下效果:

SSO英文全称Single Sign On(单点登录)。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。

它是目前比较流行的企业业务整合的解决方案之一。(本段内容来自百度百科)   话不多说,开撸!

逻辑分析:

Client1:用户A在电脑1上登录管理员账号

Service:验证用户A登陆成功生成Admin账号的Token令牌,分别存储电脑1的cookie中服务器的全局变量中(可以是session,缓存,全局变量,数据库)

Client2:用户B在电脑2上登录管理员账号

Service:验证用户B登陆成功重新生成Admin账号的Token令牌,分别存储电脑2的cookie中服务器的全局变量中(可以是session,缓存,全局变量,数据库)

Client1:触发验证:

    1,判断服务器全局变量是否过期,提示:身份信息过期,请重新登录。

    2,判断客户端的cookie是否过期,提示:长时间未登录,已下线。

    3,判断电脑1上的cookie与服务器全局变量相比是否一致。提示:此用户已在别处登陆!你被强制下线!

代码实现

Service:

1,创建一个服务器校验登录类,代码如下

using Coldairarrow.Business;
using Coldairarrow.Util;
using System;
using System.Text;
using System.Web.Mvc; namespace Coldairarrow.Web
{
/// <summary>
/// 校验登录
/// </summary>
public class CheckLoginAttribute : FilterAttribute, IActionFilter
{
public IOperator _operator { get; set; }
public ILogger _logger { get; set; } /// <summary>
/// Action执行之前执行
/// </summary>
/// <param name="filterContext">过滤器上下文</param>
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
try
{
//若为本地测试,则不需要登录
if (GlobalSwitch.RunModel == RunModel.LocalTest)
{
return;
} //判断是否需要登录
bool needLogin = !filterContext.ContainsAttribute<IgnoreLoginAttribute>(); //获取session里面的用户id
var uid = SessionHelper.Session["UserId"]?.ToString(); if (needLogin)
{
if (string.IsNullOrEmpty(uid))
{ //转到登录
RedirectToLogin(); }
else
{
var Cguid = filterContext.HttpContext.Request.Cookies["CToken"].Value?.ToString();
var Sguid = CacheHelper.Cache.GetCache(uid + "_SToken")?.ToString(); //判断是否过期
if (string.IsNullOrEmpty(Cguid) || string.IsNullOrEmpty(Sguid))
{
// 过期 转到登录
ReturnLogin("身份信息以失效,请重新登陆!");
SessionHelper.Session["UserId"] = "";
}
else
{
//判断用户是否重复登陆
if (Sguid != Cguid)
{
// 过期 转到登录
ReturnLogin("此用户已在别处登陆!你被强制下线!");
SessionHelper.Session["UserId"] = "";
//message = "已登陆";
}
} } } //if (needLogin && !_operator.Logged())
//{ //转到登录
// RedirectToLogin();
//}
//else
//{ // string Id = _operator.UserId;
// _operator.Login(Id);
// return;
//}
}
catch (Exception ex)
{
_logger.Error(ex);
RedirectToLogin();
} void RedirectToLogin()
{
if (request.IsAjaxRequest())
{
filterContext.Result = new ContentResult
{
Content = new AjaxResult { Success = false, ErrorCode = 1, Msg = "未登录" }.ToJson(),
ContentEncoding = Encoding.UTF8,
ContentType = "application/json"
};
}
else
{
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
string loginUrl = urlHelper.Content("~/Home/Login");
string script = $@"
<html>
<script>
top.location.href = '{loginUrl}';
</script>
</html>
";
filterContext.Result = new ContentResult { Content = script, ContentType = "text/html", ContentEncoding = Encoding.UTF8 };
}
} void ReturnLogin(string msg)
{
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
string loginUrl = urlHelper.Content("~/Home/Login");
string script = $@"
<html>
<script>
alert('{msg}');
top.location.href = '{loginUrl}';
</script>
</html>
";
filterContext.Result = new ContentResult { Content = script, ContentType = "text/html", ContentEncoding = Encoding.UTF8 };
}
} /// <summary>
/// Action执行完毕之后执行
/// </summary>
/// <param name="filterContext"></param>
public void OnActionExecuted(ActionExecutedContext filterContext)
{ }
}
}

2,创建一个mvc基控制器继承Controller并且引用特性【CheckLogin】

3,业务控制器继承BaseMvcController,并编写登录代码。登陆成功后调用login方法,代码如下:

        /// <summary>
/// 登录
/// </summary>
/// <param name="userId">用户逻辑主键Id</param>
public void Login(string userId)
{
//保存登陆成功的令牌
string Guid_str = "";
//分配一个唯一标识符
Guid_str = GuidHelper.GuidTo16String();
HttpContext.Current.Response.Cookies["CToken"].Value = Guid_str;
//给系统变量存储一个值,Uid代表哪个用户,GUID则是唯一标识符
CacheHelper.Cache.SetCache(userId + "_SToken", Guid_str, new TimeSpan(0, 0, 30, 0, 0), ExpireType.Absolute);
SessionHelper.Session["UserId"] = userId;
}

4,这个时候基本就结束了,还需要增加一个忽略验证的类,这个特性加在登录页面。意思是登录页面不需要触发验证;

5,服务器验证的核心代码有点不优雅,不过实现逻辑了。有问题可以评论区沟通一下。本人用的是将token分别存储在服务器缓存+客户端cookie完成  ,大家服务器上可以用session,缓存,全局变量,数据库等任意方式实现;

总结:

当用户没有重复登陆时,系统分配一个guid给用户,并记录用户id和对应的guid,这个用户在线时系统变量存储的用户id以及对应的guid值是不会变的,这时候有另外一个人用相同的账号登陆时,会改变系统变量中用户id对应的guid。

这时候服务器就判断出系统变量存储的guid与用户cookie存储的guid不同时,就会强制用户下线。

这个可以升级为指定N台设备登录,并且可以增加socket的方式通知其他电脑下线。由于业务不需要,就没有增加即时通讯。感谢观看。

Asp.Net 单点登录(SSO)|禁止重复登陆|登录强制下线的更多相关文章

  1. SSH公钥登录且禁止密码登录及更改默认端口

    1.ssh生成公私钥 ssh-keygen -t rsa -C "zhangsan@qq.com" 生成密钥的位置如下,id_rsa是私钥.id_rsa.pub是公钥: ➜ .ss ...

  2. 服务器使用ssh秘钥登录并禁止密码登录

    问题: 最近在登录服务器的时候,每次都会有提示999+ falied login等字眼,意思就是自己的服务器密码正在被人暴力破解.想象以下,别人有了你的服务器的root登录密码,那么就可以对你的服务器 ...

  3. asp.net mvc 权限过滤和单点登录(禁止重复登录)

    1.权限控制使用controller和 action来实现,权限方式有很多种,最近开发项目使用控制控制器方式实现代码如下 /// <summary> /// 用户权限控制 /// < ...

  4. 单点登录 SSO, 自动登录 , java 加密,ssl原理, Tomcat配置SSL

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 单点登录的英文简称为SSO(single sign on),单点登录功能使得用户只要登录 ...

  5. 配置sshd_config中的PermitRootLogin设置root登录或者禁止root登录

    在etc的sshd_config文件中,默认有PermitRootLogin no的配置,这个的意思是禁止root用户登录,如果想要允许root登录,需要su root用户到sshd_config下进 ...

  6. SSH使用密钥登录并禁止密码登录

    #1 新建用于登录的用户useradd -p `echo "KYmO4ClPt1" | openssl passwd -1 -salt $(< /dev/urandom tr ...

  7. SSH使用密钥登录并禁止口令登录实践

    生成PublicKey Linux:ssh-keygen -t rsa[私钥 (id_rsa) 与公钥 (id_rsa.pub)]Windows:SecurCRT/Xshell/PuTTY[SSH-2 ...

  8. 允许FTP用户登录并禁止Shell登录的方法

    最近安装了vsftpd做FTP服务,发现系统用户的登录shell设置为/sbin/nologin,就无法使用FTP服务.网上资料说,vsftpd会为每个FTP登录用户去在/etc/shells中检查对 ...

  9. SSH 使用密钥登录并禁止口令登录

    小结:修改下sshd配置文件,把公钥传上去就好了 先生成公钥和私钥,默认在/root/.ssh/目录,可以先看一下有没有这个目录. 生成公钥后,以后其它服务器也都可以复用这个公钥 最好生成时输入密码! ...

  10. Asp.Net Core基于Cookie实现同域单点登录(SSO)

    在同一个域名下有很多子系统 如:a.giant.com  b.giant.com   c.giant.com等 但是这些系统都是giant.com这个子域. 这样的情况就可以在不引用其它框架的情况下, ...

随机推荐

  1. Web前端 -- NPM包管理器

    初始化: #建立一个空文件夹,在命令提示符进入该文件夹 执行命令初始化 npm init #按照提示输入相关信息,如果是用默认值则直接回车即可. #name: 项目名称 #version: 项目版本号 ...

  2. 一个 Blink 小白的成长之路

    写在前面 写过blink sql的同学应该都有体会,明明写的时候就很顺滑,小手一抖,洋洋洒洒三百行代码,一气呵成.结果跑的时候,吞吐量就是上不去.导致数据延迟高,消息严重积压,被业务方疯狂吐槽.这时候 ...

  3. N个技巧,编写更高效 Dockerfile|云效工程师指北

    简介:云原生时代下软件的构建和部署离不开容器技术.提到容器,几乎大家下意识都会联想到 Docker .而 Docker 中有两个非常重要的概念,一个是Image(镜像),一个是Container(容器 ...

  4. 如何快速调度 PTS 的百万并发能力

    ​简介:压测是通过模拟用户行为对业务系统发起请求,测算出系统的承载能力,并对系统做一次全面的体检,压测后可根据压测表现优化系统瓶颈,防止出现线上故障. 作者:灵苒 在实际的业务场景中,压测是必不可少的 ...

  5. 阿里云张振尧:阿里云边缘云驱动5G时代行业新价值

    ​简介:近日,以"5G融合通信趋势下的技术创新"为主题的2021中国增值电信及虚拟运营高峰论坛在北京召开,阿里云边缘云高级产品专家张振尧发表了<阿里云边缘云驱动5G时代行业新 ...

  6. [Trading] 人物: 陈向忠日内交易技术核心 - 趋势形态与成交量

    分时图判断趋势(开仓方向) 只要是低点不断抬高的,就是上涨趋势,高点是否提高是其次的. 只要是高点不断降低的那就是下降趋势,假如低点也在不断降低,那么这样的下降趋势就更加完美一些. 很多人就是看对了趋 ...

  7. [PHP] 小数转科学计数法, 小数保留 n 位

    使用sprintf / printf 的 %e 或%E 格式说明符将其转换为科学计数法. 使用精度控制符指定保留多少位. 例如:sprintf('%.4e', 0.00000123); Link:ht ...

  8. [Go] 浅谈 gorm 执行 AutoMigrate 的两种时机

    第一种就是直接在操作 model 的逻辑中,执行 db.AutoMigrate,模型没有更新时不会有 schema 相关的 sql 被执行. 第二种就是单独定义一个属于 main 包的 go 文件,专 ...

  9. 如何在局域网内两台电脑上进行webapi的在线调试

    原文地址:https://www.zhaimaojun.top/Note/5475298(我自己的博客) 局域网内WebApi的远程调试方法: 第一步:管理员方式运行Vs并打开需要运行的项目,如果已经 ...

  10. minicube安装

    minicube安装 一.安装手册: https://minikube.sigs.k8s.io/docs/start/ 二.安装 打开官网,选择和自己对应的系统和要下载的版本.点击下面的release ...