背景
在企业倒退初期,企业应用的零碎很少,通常一个或者两个,每个零碎都有本人的登录模块,经营人员每天用本人的账号登录,很不便。
但随着企业的倒退,用到的零碎随之增多,经营人员在操作不同的零碎时,须要屡次登录,而且每个零碎的账号都不一样,这对于经营人员
来说,很不不便。于是,就想到是不是能够在一个零碎登录,其余零碎就不必登录了呢?这就是单点登录要解决的问题。
单点登录英文全称Single Sign On,简称就是SSO。它的解释是:在多个利用零碎中,只须要登录一次,就能够拜访其余相互信任的利用零碎。
如图所示,图中有4个零碎,别离是Application1、Application2、Application3、和SSO。Application1、Application2、Application3没有登录模块,而SSO只有登录模块,没有其余的业务模块,当Application1、Application2、Application3须要登录时,将跳到SSO零碎,SSO零碎实现登录,其余的利用零碎也就随之登录了。这完全符合咱们对单点登录(SSO)的定义。
技术实现
在说单点登录(SSO)的技术实现之前,咱们先说一说一般的登录认证机制。
如上图所示,咱们在浏览器(Browser)中拜访一个利用,这个利用须要登录,咱们填写完用户名和明码后,实现登录认证。这时,咱们在这个用户的session中标记登录状态为yes(已登录),同时在浏览器(Browser)中写入Cookie,这个Cookie是这个用户的惟一标识。下次咱们再拜访这个利用的时候,申请中会带上这个Cookie,服务端会依据这个Cookie找到对应的session,通过session来判断这个用户是否登录。如果不做非凡配置,这个Cookie的名字叫做jsessionid,值在服务端(server)是惟一的。
同域下的单点登录
一个企业个别状况下只有一个域名,通过二级域名辨别不同的零碎。比方咱们有个域名叫做:a.com,同时有两个业务零碎别离为:app1.a.com和app2.a.com。咱们要做单点登录(SSO),须要一个登录零碎,叫做:sso.a.com。
咱们只有在sso.a.com登录,app1.a.com和app2.a.com就也登录了。通过下面的登陆认证机制,咱们能够晓得,在sso.a.com中登录了,其实是在sso.a.com的服务端的session中记录了登录状态,同时在浏览器端(Browser)的sso.a.com下写入了Cookie。那么咱们怎么能力让app1.a.com和app2.a.com登录呢?这里有两个问题:
- Cookie是不能跨域的,咱们Cookie的domain属性是sso.a.com,在给app1.a.com和app2.a.com发送申请是带不上的。
- sso、app1和app2是不同的利用,它们的session存在本人的利用内,是不共享的。
那么咱们如何解决这两个问题呢?针对第一个问题,sso登录当前,能够将Cookie的域设置为顶域,即.a.com,这样所有子域的零碎都能够拜访到顶域的Cookie。咱们在设置Cookie时,只能设置顶域和本人的域,不能设置其余的域。比方:咱们不能在本人的零碎中给baidu.com的域设置Cookie。
Cookie的问题解决了,咱们再来看看session的问题。咱们在sso零碎登录了,这时再拜访app1,Cookie也带到了app1的服务端(Server),app1的服务端怎么找到这个Cookie对应的Session呢?这里就要把3个零碎的Session共享,如图所示。共享Session的解决方案有很多,例如:Spring-Session。这样第2个问题也解决了。
同域下的单点登录就实现了,但这还不是真正的单点登录。
不同域下的单点登录
同域下的单点登录是巧用了Cookie顶域的个性。如果是不同域呢?不同域之间Cookie是不共享的,怎么办?
这里咱们就要说一说CAS流程了,这个流程是单点登录的规范流程。
上图是CAS官网上的规范流程,具体流程如下:
- 用户拜访app零碎,app零碎是须要登录的,但用户当初没有登录。
- 跳转到CAS server,即SSO登录零碎,当前图中的CAS Server咱们对立叫做SSO零碎。SSO零碎也没有登录,弹出用户登录页。
- 用户填写用户名、明码,SSO零碎进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。
- SSO零碎登录实现后会生成一个ST(Service Ticket),而后跳转到app零碎,同时将ST作为参数传递给app零碎。
- app零碎拿到ST后,从后盾向SSO发送申请,验证ST是否无效。
- 验证通过后,app零碎将登录状态写入session并设置app域下的Cookie。
至此,跨域单点登录就实现了。当前咱们再拜访app零碎时,app就是登录的。接下来,咱们再看看拜访app2零碎时的流程。
- 用户拜访app2零碎,app2零碎没有登录,跳转到SSO。
- 因为SSO曾经登录了,不须要从新登录认证。
- SSO生成ST,浏览器跳转到app2零碎,并将ST作为参数传递给app2。
- app2拿到ST,后盾拜访SSO,验证ST是否无效。
- 验证胜利后,app2将登录状态写入session,并在app2域下写入Cookie。
这样,app2零碎不须要走登录流程,就曾经是登录了。SSO,app和app2在不同的域,它们之间的session不共享也是没问题的。
有的同学问我,SSO零碎登录后,跳回原业务零碎时,带了个参数ST,业务零碎还要拿ST再次拜访SSO进行验证,感觉这个步骤有点多余。他想SSO登录认证通过后,通过回调地址将用户信息返回给原业务零碎,原业务零碎间接设置登录状态,这样流程简略,也实现了登录,不是很好吗?
其实这样问题时很重大的,如果我在SSO没有登录,而是间接在浏览器中敲入回调的地址,并带上伪造的用户信息,是不是业务零碎也认为登录了呢?这是很可怕的。
总结
单点登录(SSO)的所有流程都介绍完了,原理大家都分明了。总结一下单点登录要做的事件:
- 单点登录(SSO零碎)是保障各业务零碎的用户资源的平安 。
- 各个业务零碎取得的信息是,这个用户能不能拜访我的资源。
- 单点登录,资源都在各个业务零碎这边,不在SSO那一方。 用户在给SSO服务器提供了用户名明码后,作为业务零碎并不知道这件事。 SSO轻易给业务零碎一个ST,那么业务零碎是不能确定这个ST是用户伪造的,还是真的无效,所以要拿着这个ST去SSO服务器再问一下,这个用户给我的ST是否无效,是无效的我能力让这个用户拜访。