Asp.Net 单点登录(SSO)|禁止重复登陆|登录强制下线
背景:
先上个图,看一下效果:

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)|禁止重复登陆|登录强制下线的更多相关文章
- SSH公钥登录且禁止密码登录及更改默认端口
1.ssh生成公私钥 ssh-keygen -t rsa -C "zhangsan@qq.com" 生成密钥的位置如下,id_rsa是私钥.id_rsa.pub是公钥: ➜ .ss ...
- 服务器使用ssh秘钥登录并禁止密码登录
问题: 最近在登录服务器的时候,每次都会有提示999+ falied login等字眼,意思就是自己的服务器密码正在被人暴力破解.想象以下,别人有了你的服务器的root登录密码,那么就可以对你的服务器 ...
- asp.net mvc 权限过滤和单点登录(禁止重复登录)
1.权限控制使用controller和 action来实现,权限方式有很多种,最近开发项目使用控制控制器方式实现代码如下 /// <summary> /// 用户权限控制 /// < ...
- 单点登录 SSO, 自动登录 , java 加密,ssl原理, Tomcat配置SSL
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 单点登录的英文简称为SSO(single sign on),单点登录功能使得用户只要登录 ...
- 配置sshd_config中的PermitRootLogin设置root登录或者禁止root登录
在etc的sshd_config文件中,默认有PermitRootLogin no的配置,这个的意思是禁止root用户登录,如果想要允许root登录,需要su root用户到sshd_config下进 ...
- SSH使用密钥登录并禁止密码登录
#1 新建用于登录的用户useradd -p `echo "KYmO4ClPt1" | openssl passwd -1 -salt $(< /dev/urandom tr ...
- SSH使用密钥登录并禁止口令登录实践
生成PublicKey Linux:ssh-keygen -t rsa[私钥 (id_rsa) 与公钥 (id_rsa.pub)]Windows:SecurCRT/Xshell/PuTTY[SSH-2 ...
- 允许FTP用户登录并禁止Shell登录的方法
最近安装了vsftpd做FTP服务,发现系统用户的登录shell设置为/sbin/nologin,就无法使用FTP服务.网上资料说,vsftpd会为每个FTP登录用户去在/etc/shells中检查对 ...
- SSH 使用密钥登录并禁止口令登录
小结:修改下sshd配置文件,把公钥传上去就好了 先生成公钥和私钥,默认在/root/.ssh/目录,可以先看一下有没有这个目录. 生成公钥后,以后其它服务器也都可以复用这个公钥 最好生成时输入密码! ...
- Asp.Net Core基于Cookie实现同域单点登录(SSO)
在同一个域名下有很多子系统 如:a.giant.com b.giant.com c.giant.com等 但是这些系统都是giant.com这个子域. 这样的情况就可以在不引用其它框架的情况下, ...
随机推荐
- JavaServlet类
"感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 介绍Ser ...
- 【Oracle】使用exit,return,continue跳出循环
[Oracle]使用exit,return,continue跳出循环 exit是结束循环,但还会继续执行程序包中其他的内容 return则是直接中断整个程序 continue的作用是终止本次循环,开始 ...
- 【Oracle】ORDER BY 2 DESC,1 ASC,同时对多个数据列进行不同的顺序排序&Oracle中的 (+)
最初想对 travelled_distance 降序排列 ,如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列 然后就写了下面的 SELECT U.NAME name, NVL( ...
- SQL case when then end
SQL case when then end sql中的返回值可以使用case when then end来进行实现 SELECT s.s_id, CASE s.s_name WHEN '1' THE ...
- 飞桨PaddlePaddle的安装
飞桨PaddlePaddle的安装 MacOS 下的 PIP 安装 一.环境准备 1.1 如何查看您的环境 可以使用以下命令查看本机的操作系统和位数信息: uname -m && ca ...
- 史上最强《Java 开发手册》泰山版王者归来!
阿里妹导读:潜力修炼一年之久的<Java 开发手册(泰山版)>今天发布!此次共计新增 34 条规约,修改描述 90 处,其中错误码规则更是第一次提出完整的解决方案,大家参考错误码示例表,欢 ...
- Spring RSocket:基于服务注册发现的 RSocket 负载均衡
简介: RSocket 作为通讯协议的后起之秀,核心是二进制异步化消息通讯,是否也能和 Spring Cloud 技术栈结合,实现服务注册发现.客户端负载均衡,从而更高效地实现面向服务的架构?这篇文章 ...
- 基于容器服务 ACK 发行版打造 CNStack 社区版
简介:本文将介绍如何使用 ACK Distro 作为基础镜像打造 CNStack 社区版以及CNStack 社区版中的容器服务 ACK 敏捷版产品如何帮助用户更好的使用容器平台能力. 作者:临石 C ...
- Maxcompute造数据-方法详解
简介: 造一点模拟数据的方法 概述 造数据在一些奇怪的场合会被用到.一般我们是先有数据才有基于数据的应用场合,但是反过来如果应用拿到另外一个场景,没有数据功能是没有方法演示的.一般较为真实的数据,脱敏 ...
- rerank来提升RAG的准确度的策略
RAG(Retrieval-Augmented Generation)是一种结合检索和生成两种技术的模型,旨在通过检索大规模知识库来增强文本生成任务的准确性. 要通过reranking(重排序)来提升 ...