单点登录是怎么回事

  1. 云栖社区>
  2. 博客>
  3. 正文

单点登录是怎么回事

黑白双傻 2016-05-12 13:01:41 浏览4783 评论0

摘要: 【原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源】 单点登录的解决方案有很多,各个解决方案有自己的特点。本文不是为了介绍某一种单点登录方案,只是介绍单点登录的思路,以及必要的技术基础。 一、网站登录是怎么回事 在一个普通的网站开发中,Web Server怎么知道当前用户是谁?   1. 典型WEB 在典型的WEB应用中,应用大致包含三类数据:用户数据、权限数据、业务数据。

【原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源】

单点登录的解决方案有很多,各个解决方案有自己的特点。本文不是为了介绍某一种单点登录方案,只是介绍单点登录的思路,以及必要的技术基础。

一、网站登录是怎么回事

在一个普通的网站开发中,Web Server怎么知道当前用户是谁?

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy= 

1. 典型WEB

在典型的WEB应用中,应用大致包含三类数据:用户数据、权限数据、业务数据。用户打开浏览器后,首先跳转到登录界面,登录成功后就可以继续访问。下图是一个简单的描述。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

问题来了,在登录成功后的后续访问中,服务器是怎么知道当前请求的用户到底是谁呢?我们都知道,HTTP是无连接的协议,每次浏览器的请求,对服务器来说都是一个新的请求,它怎么知道是上次登录的那个浏览器上发来的?

这就要提到两个概念:CookieSession。如果完全不懂这几个概念,自行找点编程书看看吧,还不太适合看这篇文章。

 

2. CookieSession的关系

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

在浏览器中,会维护一个CookieJavaWeb中这个Cookie名叫jsessionid。在Web Server中,会维护一个SessionMap,将一个jsessionid同一个Session对象进行绑定。这样,当浏览器访问时的jsessionid这个Cookie送到服务器后,服务器就能得到所对应的Session对象。

3. CookieSession的绑定过程

CookieSession的绑定过程如下

① 用户打开浏览器后第一次访问网站

用户第一次访问,服务器会创建一个新的Session对象和Cookie,实现二者的绑定,并将Cookie写入到用户浏览器中。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy= 

② 浏览器中后续访问时

用户后续访问时,浏览器会读出Cookie随同Request提交到服务器上,服务器根据Cookie,查找到当前浏览器对应的Session信息。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

③ 用户登录成功时

用户登录成功后,服务器会在当前用户的Session中写入用户信息。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

下次用户访问时,服务器根据Cookie得到用户的Session,就可以从中读出当前用户的信息。

4. WEB服务器集群部署会有什么问题

WEB服务器部署为集群,如果不做任何设置,用户会话可能会出现丢失。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

当用户在Server1中登录后,在Server1中创建了Session。如果下次用户被分发到Server2,这时候会无法得到Session信息,导致系统异常。

① 从前端分发处解决

让同一个浏览器发送来的请求,永远分发到同一台Server

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

 Server的Session复制

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

 Server共享Session

多个Server,可以配置使用一个共享的Session信息,比如使用Redis保存会话。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


二、单点登录需要解决哪些问题

整个应用环境,已经有很多套系统在运行,各自有自己的用户管理、登录管理。突然老板说要把所有的系统用户整合在一起,实现单点登录。怎么办?

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

1. 用户数据如何维护

原有的每个系统,都有自己的用户管理,整合单点登录后,怎么处理?大致会有以下一些处理方案:

① 各个系统中自行维护

这种方案最简单,用户管理部分不用做任何变化。但是需要做一些约定:相同的用户应该使用同一个登录名;用户在一个系统中进行了维护,必须在其他系统中同时维护。

 原有的一个主要系统中维护

原有的系统中,如果有一个侧重于用户信息管理的系统,可以将这个系统作为用户维护的主系统,其他系统不再保留用户管理功能,而改为从这个主系统中同步。

 独立一个用户管理系统

构建一套独立的用户管理系统,独立于原有的各个系统。如,使用LDAPWindows Exchange。原有的用户系统都从这套系统中进行用户同步。

2. 用户数据同步的机制

前面采用了第二或第三种方案后,需要考虑用户数据如何同步的问题。可以考虑的有几种方案。为描述方便,将负责用户管理的系统称为主系统,其他系统成为子系统。

① 主系统主动推送

各系统实现同步信息变更接口。当用户信息变更后,主系统主动向所有子系统推送用户变更信息。这样,能保证用户信息得到实时的更新。

这种方案的缺点:1、更新时某个子系统正在存在故障,更新失败,以后可能找不到更新的时机了;2、某个子系统部署位置特殊,不能被主系统访问。

 子系统定期发起同步请求

主系统实现同步接口,由子系统定期主动发起同步请求。主系统将某个时间段之后的所有变更,按照特定格式封装后返回给子系统,由子系统负责解析并更新到本地用户表。

 用户登录后访问子系统时更新个人信息

用户登录后,跳转到子系统时,从主系统中查询当前用户的信息,并同子系统进行比较,如有变更则更新本地用户信息。

这种方案的缺点:1、如果用户不访问子系统,永远没有更新的机会;2、用户被删除或禁用,没有机会更新子系统。

三种方案各有特点,可根据情况选择,或者同时用多种方案配合实现。

3. 用户权限怎么实现

用户信息统一管理后,一个随之而来的问题,就是权限信息如何管理?简单分析,大致有三种解决方案:

① 各系统自行实现权限定义和判断

这个方案最简单,对原有系统不做任何修改。

这个方案有一个缺点:各个子系统的超级管理员如何设置。原来可能是将adminroot作为超管,可能各个子系统对超管账号设置不同,就会碰到定义困难。

 将权限统一管理

在用户管理主系统中,同时定义角色、权限等信息,在主系统中实现用户权限设置,并在用户跳转到子系统时,能够准确的读取到用户在本系统中的授权信息。

这个方案对更适用于新开发的系统,权限从头开发。针对老系统改造,可能修改工作量比较大。

 主系统定义部分权限

将前面两种方案整合,可以做一个新方案:由主系统定义子系统的部分权限,更多权限由各个子系统自行定义。

比如,主系统只需定义各个子系统的超级管理员。

4. 单点登录的一些备选方案

前面分析了用户和权限的改造,它们是为统一用户做基础准备工作。现在该讨论核心问题:如何实现单点登录?

列出一些能想到的解决方案。有些方案看似问题很大,但真有人这么做,因为:做起来简单。

① 域内Cookie共享

这是利用Cookie的特点,它是按照域名存储的。如果多个应用使用的是同一个域名,则这些应用都能读取到同一个Cookie

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

如图,用户在主系统中登录后,创建一个cookie,域名设置为xyz.com。这时候,*.xyz.com的所有服务器,都能读取到这个域名。如果不指定域名,缺省使用的是主系统的域名www.xyz.com,其他子系统就不能读取同一个Cookie了。

子系统读取到userId这个cookie后,知道这是登录用户的id,从数据库中读取对应用户的信息并保存到Session中即可。

 传登陆用户的userId明文

用户在主系统中登录后,在主系统中提供子系统链接,并将用户说的唯一标识通过参数传递给子系统。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

子系统读取到这个userId后,知道这是登录用户的id,从数据库中读取对应用户的信息并保存到Session中即可。

 传登陆用户的userId密文

如果觉得传输用户的userId明文不够安全,可以考虑将参数值加密进行传输。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

子系统接收到userId参数的密文后,首先解密,知道这是登录用户的id,从数据库中读取对应用户的信息并保存到Session中即可。

 传递token替代userId

前面两种方案,通过链接传输用户ID,都不够安全。一旦黑客拿到了某个用户的userId或加密后的userId密文,他就能欺骗子系统。即使他并没有登录主系统,只需要传递同一个参数值,子系统就会认为该用户已经登陆。

因此可以设计出更安全的单点登录方案,用户访问子系统时,传递一个临时token,而不是真实的userId

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

如果用户在主系统以用户 admin 登录,在主系统中生成一个token,保存在session中,并在所有的子系统链接中增加token参数。实际登录子系统过程变成如下:

1) 浏览器访问子系统1web1.xyz.com?token=t12

2) 子系统拿到token=t12,不认识,它去问主系统:t12是谁?

3) 主系统拿到t12后,在自己维护的会话表中检查了一下,告诉子系统1:这是 admin

这样,用户就完成了登录子系统1的过程。

⑤ 使用一次性token

前面这个方案,整个会话周期,都是一个token,也不够安全。如果黑客拿到了访问第一个子系统的token,他就能在自己的浏览器中利用这个token访问第二个子系统,顺利完成登录。

这个方案针对方案4做改进,每次构造子系统链接时,生成一个新的token,当子系统验证用户成功后,立刻抛弃这个token,后续用户就不能再使用这个token进行验证。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

这个方案还有两个明显的缺点

1) token的生命周期很长,黑客有可能抢在用户登陆子系统之前用token去验证,这样黑客反而抢在了真实用户的前面登录,真实用户进不去了。

2) 需要提前在主系统中为子系统创建链接并添加token参数,不够灵活。

⑥ 使用更成熟的单点登录解决方案

前三种方案都是比较简单的处理方法,不够安全。更安全合理的做法,是基于第三方成熟的解决方案进行定制,或者是参考这些方案,设计更符合环境特点的单点登录方案。

成熟的方案,大致有:CASOAuth1.0/2.0OpenID,以及QQ等第三方提供的单点登录接入方案。

其中,CAS是一个非常成熟的解决方案,并且有JavaPHP等各种开发语言的子系统集成方案,网络上也有比较丰富的开发文档。当需要提供单点登录方案时,可以有优先考虑它,并进行必要的定制。

【云栖快讯】阿里巴巴小程序繁星计划,20亿补贴第一弹云应用免费申请,限量从速!  详情请点击

网友评论