单点登录(Single Sign On,SSO)是一种身份验证解决方案,作用是在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统
技术实现
在说单点登录(SSO)的技术实现之前,先说一说普通的登录认证机制。
普通的登录认证机制

在浏览器(Browser)中访问一个应用,这个应用需要登录,用户填写完用户名和密码后,完成登录认证。这时,服务器(Server)在这个用户的 session 中标记登录状态为 true(已登录),同时在浏览器中写入 Cookie,这个 Cookie 是这个用户的唯一标识。用户下次再访问这个应用的时候,请求中会带上这个 Cookie,服务端会根据这个 Cookie 找到对应的 session,通过 session 来判断这个用户是否登录。
同域下的单点登录
一个企业一般情况下只有一个域名,通过二级域名区分不同的系统。比如有个域名叫做: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 中记录了登录状态,同时在浏览器端的 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。 - 针对第二个问题,需要把 3 个系统的 Session 共享。共享 Session 的解决方案有很多,例如:Spring-Session、Redis

同域下的单点登录是巧用了 Cookie 顶域的特性,但这还不是真正的单点登录。
不同域下的单点登录
CAS 流程是单点登录的标准流程:

- 用户访问 app 系统,app 系统是需要登录的,但用户现在没有登录。
- 跳转到 CAS server,即 SSO 登录系统,SSO 系统也没有登录,弹出用户登录页。
- 用户填写用户名、密码,SSO 系统进行认证后,将登录状态写入 SSO 的 session,浏览器中写入 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 没有登录,而是直接在浏览器中敲入回调的地址,并带上伪造的用户信息,就可以绕过登录认证了,这是很可怕的。
上面只是以 session 为例,使用其他登录认证方式(如:Token)也是可以的
SSO 有哪些类型?
SSO 解决方案使用不同的标准和协议来对用户凭证进行验证和身份验证。
SAML
SAML(安全断言标记语言)是应用程序用来与 SSO 服务交换身份验证信息的协议或规则集。SAML 使用 XML(一种浏览器友好的标记语言)来交换用户标识数据。基于 SAML 的 SSO 服务提供更好的安全性和灵活性,因为应用程序不需要在其系统上存储用户凭证。
OAuth
OAuth(开放授权)是一种开放标准,它允许应用程序安全地从其他网站获取用户信息,而无需提供密码。应用程序不是请求用户密码,而是使用 OAuth 来获得用户访问受密码保护的数据的权限。OAuth 通过 API 建立应用程序之间的信任,允许应用程序在已建立的框架中发送和响应身份验证请求。
OIDC
OpenID 是使用一组用户凭证访问多个站点的方法。它允许服务提供商承担验证用户凭证的角色。Web 应用程序不是将身份验证令牌传递给第三方身份提供商,而是使用 OIDC 来请求附加信息并验证用户的真实性。
Kerberos
Kerberos 是一种基于票证的身份验证系统,可让两方或多方在网络上相互验证其身份。它使用安全密码学来防止未经授权访问在服务器、客户端和密钥分发中心之间传输的标识信息。