主体
单点登录的实现原理
单点登录广泛存在于当前的系统架构中。它连接了多个子系统的认证系统,实现了一个门户的多种用途。但是,单点登录的架构会有一些小问题。不同的应用环境可以采用不同的单点登录实现方案来满足需求。我给大家分享一下我遇到的应用环境,以及我在其中经历的各个阶段。如果有什么不足之处,希望大家不吝赐教。
一.分享会
共享会话是实现单点登录最直接、最简单的方式。在会话中保存用户身份验证信息,即使用存储在会话中的值作为用户凭证,这在单个站点中很正常,也很容易实现。但是在用户认证、用户信息管理和业务应用分离的场景下,会遇到单点登录的问题。在应用系统简单,子系统少的情况下,可以考虑会话共享来处理这个问题。
这个架构我使用了基于Redis的Session共享方案。将Session存储于Redis上,然后将整个系统的全局Cookie Do***in设置于顶级域名上,这样SessionID就能在各个子系统间共享。 这个方案存在着严重的扩展性问题,首先,ASP.NET的Session存储必须为SessionStateItemCollection对象,而存储的结构是经过序列化后经过加密存储的。并且当用户访问应用时,他首先做的就是将存储容器里的所有内容全部取出,并且反序列化为SessionStateItemCollection对象。这就决定了他具有以下约束: 1、 Session中所涉及的类型必须是子系统**同拥有的(即程序集、类型都需要一致),这导致Session的使用受到诸多限制; 2、 跨顶级域名的情况完全无法处理;二、基于OpenId的单点登录 这种单点登录将用户的身份标识信息简化为OpenId存放于客户端,当用户登录某个子系统时,将OpenId传送到服务端,服务端根据OpenId构造用户验证信息,多用于C/S与B/S相结合的系统,流程如下:
对于这个架构,我使用了基于Redis的会话共享方案。会话存储在Redis上,然后在顶级域上设置整个系统的全局Cookie域,这样SessionID就可以在子系统之间共享了。这个方案有严重的可扩展性问题。首先,ASP.NET的会话存储必须是SessionStateItemCollection对象,序列化后加密存储结构。而当用户访问应用程序时,他做的第一件事就是取出存储容器中的所有内容,并将它们反序列化为SessionStateItemCollection对象。这就决定了他有以下约束:1。Session涉及的类型必须是子系统共享的(即程序集和类型需要一致),导致Session的使用受到很多限制;2.跨顶级域名完全无法管理;二。基于OpenId的单点登录。这种单点登录将用户的身份信息简化为OpenId并存储在客户端。当用户登录一个子系统时,OpenId被传送到服务器,服务器根据OpenId构造用户认证信息,这在C/S和B/S相结合的系统中多被使用,流程如下:
从上图可以看出,这套单点登录依赖于OpenId的交付,其验证是基于OpenId的存储和发送。
1.当用户第一次登录时,将用户名和密码发送给验证服务;
2.验证服务向客户端返回用户标识OpenId
3.客户端存储;
4.访问子系统时,向子系统发送OpenId
5.子系统将OpenId转发给验证服务;
6.验证服务将用户认证信息返回给子系统;
7.在子系统构建了用户认证信息之后,它将授权内容返回给客户端。
这种单点登录验证机制的主要问题是,它将用户的OpenId存储在基于C/S架构的客户端,并在子系统之间发送OpenId。但是,在B/S模式下很难做到这一点。为了处理这个问题,我们将介绍下一个方法,它将解决B/S模式下OpenId的存储和交付问题。
第三,基于Cookie的OpenId存储方案
我们知道,cookies的作用是充当信息载体,在服务器和浏览器之间传递信息,cookies一般以域名来划分。比如a.xxx.com和b.xxx.com的cookie不能互相访问,但是子域名可以访问上级域名的cookie。也就是说,a.xxx.com和b.xxx.com可以访问xxx.com下的cookie,所以他们可以使用顶级域名的cookie作为OpenId的载体。
验证步骤与上述第二种方法非常相似:
1.登录提供验证服务的网站;
2.将OpenId写入顶级域Cookie
3.访问子系统(带有OpenId的Cookie)
4.子系统取出OpenId并将其发送给验证服务。
5.返回用户验证信息。
6.返回授权内容。
在以上两种方法中,我们可以看到会话共享方案中的类型等问题被OpenId解耦,构造用户认证信息会更加灵活,子系统之间的认证相互独立。但在第三种方案中,我们是基于所有子系统都是同一个顶级域名的假设,在实际生产环境中有多个域名是很正常的,所以不得不考虑如何解决跨域问题。
四。B/S多域环境下的单点登录处理
在有多个顶级域名的情况下,我们将无法共享每个子系统的OpenId。处理B/S环境下的跨域问题,首先要想到JSONP方案。
验证步骤如下:1 .用户通过登录子系统登录;2.用户登录子系统记录用户的登录状态、OpenId等信息;3.用户使用业务子系统;4.如果用户没有登录业务子系统,则跳转到用户登录子系统;5.用户子系统通过JSONP接口将用户OpenId发送给业务子系统;6.业务子系统通过OpenId调用验证服务;7.认证服务返回认证信息,业务子系统构造用户登录凭证;(此时,用户客户端已经与子业务系统的验证信息一一对应)8。将用户登录结果返回给用户登录子系统,如果登录成功,则跳转回业务子系统;9.将授权内容返回给客户端;
动词 (verb的缩写)安全问题
经过以上步骤,可以解决跨域情况下的单点登录问题。在整个开发过程的开始,我们使用用户表中记录的一个OpenId字段来保存用户的OpenId。然而,在这种机制下,显然存在一些安全性和可扩展性问题。这个扩展性问题主要体现在一个方面:OpenId安全性和用户体验的矛盾。整个单点登录机制决定了OpenId会出现在客户端,所以OpenId需要有一个过期机制。如果用户在一个终端登录,他可以选择每次登录或注销时刷新OpenId。但是在多终端登录的情况下,会出现一个矛盾:当一个终端刷新OpenId时,其他终端将无***常授权。最终我采用了单用户多OpenId的方案。用户每次通过用户名/密码登录,都会生成一个OpenID存储在Redis中,并设置过期时间,这样多个OpenId将对应多个终端登录,一个OpenId失败,所有终端验证失败的情况将不复存在。
请在留言区留下您的看法,共同讨论改进。如果今天的文章给了你学习能力提升的新启发和新知识,请分享给更多的人。
欢迎读者加入程序员小乐科技群,在微信官方账号后台回复“加群”或“学习”即可。
估计你还想看吧?
阿里、腾讯、百度、华为、JD.COM最新面试问题合集
Java Web开发必须掌握的三项技术:Token、Cookie、Session!
关注系统架构的三大误区。就看这篇文章吧!
Java内存管理,看这篇文章就知道了!
本文来自白云揉碎投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/522652.html