基础编程学习快乐每一天
首页
留言
Siddim.com
当前位置:
首页
>
编程知识库
>
后端开发知识
>
谈谈项目中单点登录的实现原理?
谈谈项目中单点登录的实现原理?
阅读
1
2019-11-02
作者: 一叶知秋
https
://
muyinchen
.
github
.
io
注:单点登录原理是一个重要知识点,也常被问及,很多童鞋照葫芦画瓢搭建过单点登录,但是被问到原理时可能说不出来,下面简单介绍,抛砖引玉,希望对大家有所帮助。
单点登录在现在的系统架构中广泛存在,他将多个子系统的认证体系打通,实现了一个入口多处使用,而在架构单点登录时,也会遇到一些小问题,在不同的应用环境中可以采用不同的单点登录实现方案来满足需求。
我将以我所遇到的应用环境以及在其中所经历的各个阶段与大家分享,若有不足,希望各位不吝赐教。
一、共享Session
共享
Session
可谓是实现单点登录最直接、最简单的方式。将用户认证信息保存于
Session
中,即以
Session
内存储的值为用户凭证,这在单个站点内使用是很正常也很容易实现的,而在用户验证、用户信息管理与业务应用分离的场景下即会遇到单点登录的问题,在应用体系简单,子系统很少的情况下,可以考虑采用
Session
共享的方法来处理这个问题。
这个架构我使用了基于
Redis
的
Session
共享方案。将
Session
存储于
Redis
上,然后将整个系统的全局
Cookie
Domain
设置于顶级域名上,这样
SessionID
就能在各个子系统间共享。
这个方案存在着严重的扩展性问题,首先,
ASP
.
NET
的
Session
存储必须为
SessionStateItemCollection
对象,而存储的结构是经过序列化后经过加密存储的。
并且当用户访问应用时,他首先做的就是将存储容器里的所有内容全部取出,并且反序列化为
SessionStateItemCollection
对象。这就决定了他具有以下约束:
Session
中所涉及的类型必须是子系统中共同拥有的(即程序集、类型都需要一致),这导致
Session
的使用受到诸多限制;
跨顶级域名的情况完全无法处理;
二、基于OpenId的单点登录
这种单点登录将用户的身份标识信息简化为
OpenId
存放于客户端,当用户登录某个子系统时,将
OpenId
传送到服务端,服务端根据
OpenId
构造用户验证信息,多用于
C
/
S
与
B
/
S
相结合的系统,流程如下:
由上图可以看到,这套单点登录依赖于
OpenId
的传递,其验证的基础在于
OpenId
的存储以及发送。
当用户第一次登录时,将用户名密码发送给验证服务;
验证服务将用户标识
OpenId
返回到客户端;
客户端进行存储;
访问子系统时,将
OpenId
发送到子系统;
子系统将
OpenId
转发到验证服务;
验证服务将用户认证信息返回给子系统;
子系统构建用户验证信息后将授权后的内容返回给客户端。
这套单点登录验证机制的主要问题在于他基于
C
/
S
架构下将用户的
OpenId
存储于客户端,在子系统之间发送
OpenId
,而
B
/
S
模式下要做到这一点就显得较为困难。为了处理这个问题我们将引出下一种方式,这种方式将解决
B
/
S
模式下的
OpenId
的存储、传递问题。
三、基于Cookie的OpenId存储方案
我们知道,
Cookie
的作用在于充当一个信息载体在
Server
端和
Browser
端进行信息传递,而
Cookie
一般是以域名为分割的,例如
a
.
xxx
.
com
与
b
.
xxx
.
com
的
Cookie
是不能互相访问的,但是子域名是可以访问上级域名的
Cookie
的。即
a
.
xxx
.
com
和
b
.
xxx
.
com
是可以访问
xxx
.
com
下的
Cookie
的,于是就能将顶级域名的
Cookie
作为
OpenId
的载体。
验证步骤和上第二个方法非常相似:
在提供验证服务的站点里登录;
将
OpenId
写入顶级域名
Cookie
里;
访问子系统(
Cookie
里带有
OpenId
)
子系统取出
OpenId
通过并向验证服务发送
OpenId
返回用户认证信息
返回授权后的内容
在以上两种方法中我们都可以看到通过
OpenId
解耦了
Session
共享方案中的类型等问题,并且构造用户验证信息将更灵活,子系统间的验证是相互独立的,但是在第三种方案里,我们基于所有子系统都是同一个顶级域名的假设,而在实际生产环境里有多个域名是很正常的事情,那么就不得不考虑跨域问题究竟如何解决。
四、B/S多域名环境下的单点登录处理
在多个顶级域名的情况下,我们将无法让各个子系统的
OpenId
共享。处理
B
/
S
环境下的跨域问题,我们首先就应该想到
JSONP
的方案。
验证步骤如下:
用户通过登录子系统进行用户登录;
用户登录子系统记录了用户的登录状态、
OpenId
等信息;
用户使用业务子系统;
若用户未登录业务子系统则将用户跳转至用户登录子系统;
用户子系统通过
JSONP
接口将用户
OpenId
传给业务子系统;
业务子系统通过
OpenId
调用验证服务;
验证服务返回认证信息、业务子系统构造用户登录凭证;(此时用户客户端已经与子业务系统的验证信息已经一一对应)
将用户登录结果返回用户登录子系统,若成功登录则将用户跳转回业务子系统;
将授权后的内容返回客户端;
五、安全问题
经过以上步骤,跨域情况下的单点登录问题已经可以得到解决。而在整个开发过程初期,我们采用用户表中记录一个
OpenId
字段来保存用户
OpenId
,而这个机制下很明显存在一些安全性、扩展性问题。这个扩展性问题主要体现在一个方面:
OpenId
的安全性和用户体验的矛盾。
整个单点登录的机制决定了
OpenId
是会出现在客户端的,所以
OpenId
需要有过期机制,假如用户在一个终端登录的话可以选择在用户每次登录或者每次退出时刷新
OpenId
,而在多终端登录的情况下就会出现矛盾:当一个终端刷新了
OpenId
之后其他终端将无法正常授权。
而最终,我采用了单用户多
OpenId
的解决方案。每次用户通过用户名/密码登录时,产生一个
OpenId
保存在
Redis
里,并且设定过期时间,这样多个终端登录就会有多个
OpenId
与之对应,不再会存在一个
OpenId
失效所有终端验证都失效的情况。
最近三期
【
09
期】说说
hashCode
() 和
equals
() 之间的关系?
【
10
期】
Redis
面试常见问答
【
11
期】分布式系统接口,如何避免表单的重复提交?
以上数据来源于网络,如有侵权,请联系删除。
上一篇:
分布式系统接口,如何避免表单的重复提交?
下一篇:
谈谈 Redis 的过期策略
评论
(0)
提交
类别
基础编程学习
HTML
PHP
Python
编程知识库
后端开发知识
热门文章
Java并发中的同步容器与并发容器,你了解多少?
Innodb中的事务隔离级别和锁的关系,难倒一半面试者!
SpringBoot + minio实现分片上传、秒传、续传
面试官:你知道消息队列如何保证数据不丢失吗?
JAVA知识 Java8新特性
面试官:谈谈为什么要限流,有哪些限流方案?
说说动态代理与静态代理区别
面试官:思考Tomcat 类加载器为什么要违背双亲委派模型?
boot-admin 基于SpringBoot的后台权限管理系统,可作为脚手架,用于快速搭建项目
SpringBoot+Vue+App+硬件实现智能家居系统项目