为什么需要SSO
首先看看什么叫SSO,也即一次登录、多次使用。
比如一个公司内部有很多个管理系统,这些系统在功能上互相独立,我们可以对每个系统做一套独立的账号系统,但是这样做,每个用户需要申请多个账号,并且每打开一个新系统的页面都需要登录,非常繁琐。 而且由于账号分散到各个系统,也不利于权限的统一管理。
如下图:
![482fd293e3ab8fc6b6b678e3cffc1b8a.png](https://img-blog.csdnimg.cn/img_convert/482fd293e3ab8fc6b6b678e3cffc1b8a.png)
所以,我们需要一个系统能够解决以上问题,我们将该问题拆解成如下几个子问题进行解决。
单系统保持登录状态
首先看看最简单的一个问题,某个系统M,如果用户A已经登录,关闭该系统页面,并重新打开,如何自动登录。
![fde552ef8506384afdfa56a2a9e217a1.png](https://img-blog.csdnimg.cn/img_convert/fde552ef8506384afdfa56a2a9e217a1.png)
用户通过浏览器访问系统M,能不能在浏览器侧保存某种信息,以记录用户的登录状态?
可以的,浏览器可以保存数据到cookie中,并进行持久存储,那么可以将用户登录状态保存其中。
用户首次访问系统M,由于未登录,弹出登录框,用户输入账号、密码信息,后台系统验证通过后,生成一个带有效期的SessionID信息,并将其下发给client侧,后者将其保存在cookie中,之后的请求中均带上SessionID信息,这样服务器侧根据该信息就知道用户具体信息,而不需要用户再次登录。
![f3d834e60f8ea94ee934710a59db3058.png](https://img-blog.csdnimg.cn/img_convert/f3d834e60f8ea94ee934710a59db3058.png)
这样当用户再次访问系统M时,首先检查cookie信息,并将其与服务器校验有效性,如果其依然处于有效期,则不用输入账号、密码,直接登录成功。
多系统保持登录状态
这里的多系统分为两种情况:
- 多个系统处于同一个域名下,例如:公司内部的管理系统,http://m.oa.com,http://n.oa.com
- 多个系统域名不同,例如:微信、QQ均可以采用某种账号登录,http://m.wx.com,http://m.qq.com
同域名登录
在之前的讨论中,用户访问M系统(http://m.oa.com),在其输入账号、密码并登录成功后,其将服务器下发的SessionID信息保存到cookie中,这时候保存的域为m.oa.com
,要想实现同域下的访问,只需要将cookie保存的域更改为.oa.com
即可。
如此之后,用户访问N系统(http://n.oa.com),由于两者处于同一个域下,即可访问刚才由M系统保存的cookie信息,从而实现自动登录。
![50c755ff647bf73dcd100638bf755b07.png](https://img-blog.csdnimg.cn/img_convert/50c755ff647bf73dcd100638bf755b07.png)
跨域名登录
不同域名的两个系统如何实现单点登录?根据浏览器cookie规则,不允许跨域访问,主要是为了安全性。 我们想象一下,如果不采用SSO单点登录,那么用户登录两个系统,http://m.wx.com,http://m.qq.com,均需要输入账号、密码,而这个账号密码页的域名是同一个,http://sso.oa.com。
那么我们能不能借助该共同信息,以实现SSO单点登录。
答案是可以的,只是由于跨域和安全性问题,流程比较复杂,具体流程如下:
用户->域名M:请求访问
域名M->域名SSO:用户未登录,重定向到登录界面
域名SSO->SSO后台:用户输入账号、密码并登录
SSO后台->域名SSO:信息校验成功,生成SessionID,并针对域名M生成ticket_M
域名SSO->域名SSO:将SessionID保存到cookie的sso.oa.com域下
域名SSO->域名M:重定向,并传递参数ticket_M
域名M->M后台:将参数ticket_M传递
M后台->SSO后台:校验ticket_M合法性
SSO后台->M后台:校验通过
M后台->域名M:登录成功
域名M->域名M:保存ticket_M到cookie的m.wx.com域下
域名M->M后台:其它请求
用户在此之后,如果再次访问域名M,由于该域的cookie下有登录ticket,只需要拿着该ticket向服务器进行校验,即可实现自动登录。
在此之后,如果用户访问跨域页面N,看看如何自动登录:
用户->域名N:请求访问
域名N->域名SSO:用户未登录,重定向到登录界面
域名SSO->域名SSO:由于SSO域名的cookie下,有已登录的SessinID信息
域名SSO->用户:询问是否授权登录
用户->域名SSO:授权登录
域名SSO->SSO后台:拿着SessionID进行校验
SSO后台->域名SSO:信息校验成功,针对域名N生成ticket_N
域名SSO->域名N:重定向,并传递参数ticket_N
域名N->N后台:将参数ticket_N传递
N后台->SSO后台:校验ticket_N合法性
SSO后台->N后台:校验通过
N后台->域名N:登录成功
域名N->域名N:保存ticket_N到cookie的m.qq.com域下
域名N->N后台:其它请求
如此,即实现了域名N的自动登录。
核心
- 将公用登录SessionID信息保存到登录页面SSO域的cookie中
- 各自系统的登录状态、ticket信息保存到各自域的cookie中
- 各个系统生成独立的ticket,主要是为了避免cookie泄漏等漏洞。避免黑客攻破一个系统M,拿到cookie信息,即可自动登录其它系统。
- 已登录状态下,SSO页面会询问用户是否授权登录另一系统N