共计 2731 个字符,预计需要花费 7 分钟才能阅读完成。
背景
在企业倒退初期,企业应用的零碎很少,通常一个或者两个,每个零碎都有本人的登录模块,经营人员每天用本人的账号登录,很不便。
但随着企业的倒退,用到的零碎随之增多,经营人员在操作不同的零碎时,须要屡次登录,而且每个零碎的账号都不一样,这对于经营人员
来说,很不不便。于是,就想到是不是能够在一个零碎登录,其余零碎就不必登录了呢?这就是单点登录要解决的问题。
单点登录英文全称 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 是否无效,是无效的我能力让这个用户拜访。