背景

在企业倒退初期,企业应用的零碎很少,通常一个或者两个,每个零碎都有本人的登录模块,经营人员每天用本人的账号登录,很不便。
但随着企业的倒退,用到的零碎随之增多,经营人员在操作不同的零碎时,须要屡次登录,而且每个零碎的账号都不一样,这对于经营人员
来说,很不不便。于是,就想到是不是能够在一个零碎登录,其余零碎就不必登录了呢?这就是单点登录要解决的问题。

单点登录英文全称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官网上的规范流程,具体流程如下:

  1. 用户拜访app零碎,app零碎是须要登录的,但用户当初没有登录。
  2. 跳转到CAS server,即SSO登录零碎,当前图中的CAS Server咱们对立叫做SSO零碎。SSO零碎也没有登录,弹出用户登录页。
  3. 用户填写用户名、明码,SSO零碎进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。
  4. SSO零碎登录实现后会生成一个ST(Service Ticket),而后跳转到app零碎,同时将ST作为参数传递给app零碎。
  5. app零碎拿到ST后,从后盾向SSO发送申请,验证ST是否无效。
  6. 验证通过后,app零碎将登录状态写入session并设置app域下的Cookie。

至此,跨域单点登录就实现了。当前咱们再拜访app零碎时,app就是登录的。接下来,咱们再看看拜访app2零碎时的流程。

  1. 用户拜访app2零碎,app2零碎没有登录,跳转到SSO。
  2. 因为SSO曾经登录了,不须要从新登录认证。
  3. SSO生成ST,浏览器跳转到app2零碎,并将ST作为参数传递给app2。
  4. app2拿到ST,后盾拜访SSO,验证ST是否无效。
  5. 验证胜利后,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是否无效,是无效的我能力让这个用户拜访。