SSO(Single Sign On)单点登录
一、先讲一讲 Token 和 Cookies 的区别
-
基于Cookies的认证程序
用户带着账号密码等信息登录
-
服务器验证登录信息正确后,创建一个会话,设置为登录状态, 返回会话的ID, 同时自己把这个会话储存在自己的数据库中。
HttpSession session = request.getSession(); session.setAttribute("isLogin",true);
浏览器设置一个cookie,以key/value的形式储存下这个会话ID 如图中 Cookie: session=.....
-
后续请求中,服务器根据这个会话ID,在自己数据库里面查询,看该会话是否为登录状态
HttpSession session = request.getSession(); session.setAttribute("isLogin",true);
用户退出网站时,浏览器和服务器同时销毁这个会话
二、多系统的复杂性
上面的那个cookie机制应该很好理解,早期服务器确实也是用那种机制,像Tomcat. 但是web系统早已经从久远的单系统发展成如今多系统组成的应用群。
面对这么多的系统,用户总不可能一个个登录,再一个个注销吧。实际上复杂性应该由系统内部承担,对于用户而言,系统看上去就是一个整体,和单系统一样,登录/注销只需要一次就行.
单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送http请求时会自动携带与该域匹配的cookie,而不是所有cookie
域,你就简单理解成后面用 . 分割的东西吧。(一个域名是由几部分,有可能只是一部分,也许是两部分,三部分...)组成的简单结构,它被点分隔,并需要从右到左阅读。)比如. com,.org就是顶级域名,然后顶级域名前面的就是二级域名。比如 mozilla.org, 然后后面还可以接developer.mozilla.org。
需要特别注意的是:images.google.com与www.google.com同属于google,但是他们的域名不一样,二者同样也不能操作彼此的Cookie,浏览器在访问的时候,会根据访问地址自动携带相关域名的cookie过去。
所以你发现如果跨域访问的话是不是很麻烦,又要登录一次。例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯掉。
既然这样,为什么不将web应用群中所有子系统的域名统一在一个顶级域名下,如“.baidu.com”,然后将它们的cookie域设置为“baidu.com”,这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享cookie的方式。
然而,可行并不代表好,共享cookie的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间;第三,cookie本身不安全。
那这时候你会不会想,不如引入第三方服务器,帮我们管理登录认证,就像签发SSL证书那样。嗯,确实,这就是后来的发展出的单点登录。
三、单点登录
什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分。
例如访问在网易账号中心(http://reg.163.com/ )登录之后 访问以下站点都是登录状态
网易直播 http://v.163.com
网易博客 http://blog.163.com
网易花田 http://love.163.com
网易考拉 https://www.kaola.com
-
网易Lofter http://www.lofter.com
注意到他们跨域了对不对,二级域名不一样
业务逻辑一般是这个样子
数据库是用于储存用户账户信息
Redis储存登录信息,通常是将UserId,UserName缓存起来
现在,假设你在主域名那里登录,具体情况就是这样的。
这里注意下域名是 test.com,Cookie 就认准了是这个域名. (domian=test.com) 但是跨域访问的时候Cookie不能跨域,这时候SSO中心签发的 AuthToken是全局通用的,这时候也叫创建的全局会话。下面会讲区别
后期你要获取受保护的资源,登录信息的验证就是这样的
然后重点来了,假设你在主域名站点那里刚登录过,然后你跨域访问 testX.com 这个域名
这里就开始发挥SSO的作用了
为什么一开始不能从Cookie中获取AuthToken? 因为此Cookie非彼Cookie 这时候的Cookie的domian=testX.com. 而之前我们在主域名站点登录保存的Cookie的domian=test.com.
后面几部发现浏览器把 AuthToken(全局有效的令牌)放在了 domian=testX.com的Cookie中,这时候就创建了局部会话。
然后是单点登出,我们介绍一种复杂点的情况,就是在子系统中跨域登出
你会发现,你在子系统中登出,会先把你重定向到主域名的站点那里,然后把Cookie里面的AuthToken弄过期,同时清除Redis里面登录信息的缓存。
那个全局通用的令牌过期后,其他子系统对应的Cookie中储存的AuthToken就也没用了,因为本来就是同一个嘛。最后一步就是给你重定向到最初的登录页面去。
所以,可以得出结论
局部会话存在,全局会话一定存在
全局会话存在,局部会话不一定存在
全局会话销毁,局部会话必须销毁
在一个子系统中注销,所有子系统的会话都会被注销
以上是一般的SSO原理。
然后特别要提一下的是耶鲁大学研发的CAS框架:CAS(Central Authentication Service)是基于Kerberos票据方式实现SSO单点登录的框架。 和我上面讲的原理略有些不同,比较麻烦
具体想了解实现细节的请参考
https://blog.csdn.net/readiay/article/details/52856510
因为我之前在云平台爬学生照片的时候就碰到这种登录机制。 当时用最简单的模拟表单登录一直拿不到Cookie。 像这样
一堆的302重定向
[]
看那个网址里面的cas,就是CAS实现的单点登录
这是其中一个重定向后获取的参数。 Cookies是键值对的储存形式,就像go语言里面的map。根据CAS机制,重定向后得到TGC啥的放在Cookies里面,所以Cookies里面好几个键值对。
不过还好GO语言有一个叫做CookieJar的包,可以模拟浏览器行为,自动重定向并且记下每一个网站给个Cookies. 不过我没试过,后来老板给了我教程,我爬珍爱网去了,,,
最后图的出处和相关内容引用有
Cookies vs Tokens 权威指导:https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide 是一篇英文文章,讲Cookies和Token的区别优劣,讲的很好很详细,里面的单词也不难
https://cloud.tencent.com/developer/article/1166255 两篇SSO原理相关文章
https://cloud.tencent.com/developer/article/1333892