单点登陆在如今的系统架构中普遍存在,他将多个子系统的认证体系打通,实现了一个入口多处使用,而在架构单点登陆时,也会遇到一些小问题,在不一样的应用环境中能够采用不一样的单点登陆实现方案来知足需求。我将以我所遇到的应用环境以及在其中所经历的各个阶段与你们分享,如有不足,但愿各位不吝赐教。跨域
1、共享Session安全
共享Session可谓是实现单点登陆最直接、最简单的方式。将用户认证信息保存于Session中,即以Session内存储的值为用户凭证,这在单个站点内使用是很正常也很容易实现的,而在用户验证、用户信息管理与业务应用分离的场景下即会遇到单点登陆的问题,在应用体系简单,子系统不多的状况下,能够考虑采用Session共享的方法来处理这个问题。架构
这个架构我使用了基于Redis的Session共享方案。将Session存储于Redis上,而后将整个系统的全局Cookie Domain设置于顶级域名上,这样SessionID就能在各个子系统间共享。加密
这个方案存在着严重的扩展性问题,首先,ASP.NET的Session存储必须为SessionStateItemCollection对象,而存储的结构是通过序列化后通过加密存储的。而且当用户访问应用时,他首先作的就是将存储容器里的全部内容所有取出,而且反序列化为SessionStateItemCollection对象。这就决定了他具备如下约束:spa
一、 Session中所涉及的类型必须是子系统中共同拥有的(即程序集、类型都须要一致),这致使Session的使用受到诸多限制;对象
二、 跨顶级域名的状况彻底没法处理;blog
2、基于OpenId的单点登陆接口
这种单点登陆将用户的身份标识信息简化为OpenId存放于客户端,当用户登陆某个子系统时,将OpenId传送到服务端,服务端根据OpenId构造用户验证信息,多用于C/S与B/S相结合的系统,流程以下:内存
由上图能够看到,这套单点登陆依赖于OpenId的传递,其验证的基础在于OpenId的存储以及发送。开发
一、当用户第一次登陆时,将用户名密码发送给验证服务;
二、验证服务将用户标识OpenId返回到客户端;
三、客户端进行存储;
四、访问子系统时,将OpenId发送到子系统;
五、子系统将OpenId转发到验证服务;
六、验证服务将用户认证信息返回给子系统;
七、子系统构建用户验证信息后将受权后的内容返回给客户端。
这套单点登陆验证机制的主要问题在于他基于C/S架构下将用户的OpenId存储于客户端,在子系统之间发送OpenId,而B/S模式下要作到这一点就显得较为困难。为了处理这个问题咱们将引出下一种方式,这种方式将解决B/S模式下的OpenId的存储、传递问题。
3、基于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共享方案中的类型等问题,而且构造用户验证信息将更灵活,子系统间的验证是相互独立的,可是在第三种方案里,咱们基于全部子系统都是同一个顶级域名的假设,而在实际生产环境里有多个域名是很正常的事情,那么就不得不考虑跨域问题究竟如何解决。
4、B/S多域名环境下的单点登陆处理
在多个顶级域名的状况下,咱们将没法让各个子系统的OpenId共享。处理B/S环境下的跨域问题,咱们首先就应该想到JSONP的方案。
验证步骤以下:
一、 用户经过登陆子系统进行用户登陆;
二、 用户登陆子系统记录了用户的登陆状态、OpenId等信息;
三、 用户使用业务子系统;
四、 若用户未登陆业务子系统则将用户跳转至用户登陆子系统;
五、 用户子系统经过JSONP接口将用户OpenId传给业务子系统;
六、 业务子系统经过OpenId调用验证服务;
七、 验证服务返回认证信息、业务子系统构造用户登陆凭证;(此时用户客户端已经与子业务系统的验证信息已经一一对应)
八、 将用户登陆结果返回用户登陆子系统,若成功登陆则将用户跳转回业务子系统;
九、 将受权后的内容返回客户端;
5、安全问题
通过以上步骤,跨域状况下的单点登陆问题已经能够获得解决。而在整个开发过程初期,咱们采用用户表中纪录一个OpenId字段来保存用户OpenId,而这个机制下很明显存在一些安全性、扩展性问题。这个扩展性问题主要体如今一个方面:OpenId的安全性和用户体验的矛盾。
整个单点登陆的机制决定了OpenId是会出如今客户端的,因此OpenId须要有过时机制,假如用户在一个终端登陆的话能够选择在用户每次登陆或者每次退出时刷新OpenId,而在多终端登陆的状况下就会出现矛盾:当一个终端刷新了OpenId以后其余终端将没法正常受权。而最终,我采用了单用户多OpenId的解决方案。每次用户经过用户名/密码登陆时,产生一个OpenId保存在Redis里,而且设定过时时间,这样多个终端登陆就会有多个OpenId与之对应,再也不会存在一个OpenId失效全部终端验证都失效的状况。
这是我开发的系统中单点登陆经历过的一个个步骤,这里分享给你们,但愿对你们能有所帮助,若是有任何遗漏、错误但愿你们指出,须要深刻交流能够在回复中提出,我将尽力给予解答。谢谢。
本文欢迎转载,在转载时请注明做者、出处。