单点登录(SSO,Single Sign On)对我们来说已经不陌生了,一次登录,处处登录。企业旗下都是自己的应用系统,所有的应用系统都使用同一个一级域名,通过不同的二级域名来区分应用系统。例如:百度,百度下面有很多子系统——百度文本库、百度知道等。在我们的体验中,登录了百度帐号,其他子应用系统也就随之登录了。这次,让我们了解下背后实现原理--同域下的单点登录。
同域 SSO 原理设计

门户系统设置 Cookie 的 domain 为一级域名authing.com,这样就可以将门户的 Cookie 共享给所有使用该域名(authing.com)的系统。
使用 Spring Session 等技术让所有系统共享 Session。
门户系统登录之后,无论是跳转应用一还是应用二,都能通过门户 Cookie 中的 SessionId 读取到 Session 中的登录信息,实现单点登录。
门户系统设置 Cookie 的 domain 为一级域名authing.com,这样就可以将门户的 Cookie 共享给所有使用该域名(authing.com)的系统。
使用 Spring Session 等技术让所有系统共享 Session。
门户系统登录之后,无论是跳转应用一还是应用二,都能通过门户 Cookie 中的 SessionId 读取到 Session 中的登录信息,实现单点登录。
同域 SSO 原理分析
HTTP 协议是无状态的,单个系统的会话由服务端 Session 进行维持,Session 保持会话的原理是通过给浏览器返回 Set-Cookie 请求头,浏览器收到后把包含 Sessionid 的 Cookie 写入浏览器,每次访问都会自动携带该站点下的 Cookie,在服务端读取其中的 Sessionid 进行验证,实现会话保持。通过巧用 Cookie 顶域的特性和 Session 共享,可以实现同域下的多个系统登录认证,也就是同域下的单点登录。
Session-Cookie 机制
服务端通过 Cookie 认证客户端。 用户在第一次登录后,服务端将返回一个 Cookie 给客户端(这个 Cookie 包含 Sessionid),用户下一次发起请求后将在 header 带上这个 Cookie,服务端便可以识别出具体的客户端。
Spring-Session 共享
解决同域下集群 Session 共享的问题。当服务端为集群而不是单点的时候,需要集群服务器之间的 Session 共享才能实现 Session-Cookie 机制的同域 SSO。 实现方式:通过过滤器拦击请求,获取 Session 数据并保存到数据库(Session 持久化),之后 Session 数据将统一从数据库中获取。
同域 SSO 验证方式
同一个域名下的不同站点是如何进行验证
根据浏览器的 Cookie 同源规则,两个站点是可以共享 Cookie 的,前提是这两个站点在同一个域名(或者二级域名)下。
这种同域下的 Cookie,浏览器会将 Cookie 以及 Cookie 所属的域存在本地。当对该域下的任何子站点进行访问的时候,浏览器会将这些 Cookie 发送给站点系统。
假设:我们有两个站点www.authing.com/site1,www.authing.com/site2。这两个站点共享同一个主机地址,并且二者在同一域名下。
登录www.authing.com/site1,浏览器会有一个来自www.auhting.com/site1的身份鉴证的 Cookie。当你点击 site1 下的任何子页面的时候,这些 Cookie 都会发送给site1。
当请求www.authing.com/site2的时候,对于 site2 下面的任何子页面,这些 Cookie 也同样会随着请求发送过去。
当浏览器端存储的 Cookie 的域是www.authing.com的时候,site1 和 site2 两个站点是同属于该域的。所以对于该域下的 Cookie,两个站点都可以得到。只要它们的 Session 信息是保存在同一个地方即可。
同一个域名下不同的子域如何进行验证
假设:我们的站点是按照下面的域名进行部署的sub1.auhting.com,sub2.authing.com, 这两个站点共享同一域authing.com。 默认情况下,浏览器会发送给 Cookie 所属域所对应的主机。也就是说,sub1.auhting.com,sub2.authing.com的 Cookie 的默认所属域是不同的,因此我们需要在服务端通过设置 Cookie domain 来进行处理。
登录sub1.authing.com系统。
登录成功以后,设置 Cookie 信息。我们将 SessionId 存到 Cookie 中,同时必须将这 个Cookie 的所属域设置为顶级域 .authing.com。
访问sub2.authing.com系统,浏览器会将 Cookie 中的信息 SessionId 附带在请求中一同发送到sub2.authing.com系统。这时该系统会检查到 Session 为已登录状态,然后放行。
当然,登录sub2.authing.com的方式也是相同的。经过上面的步骤就可以实现不同二级域名的单点登录了。 百度系列应用的单点登录 下面我们通过一个具体的例子来体会一下同域下不同应用的单点登录和单点登出,这次我们选择了百度知道和百度网盘。 我们登录百度网盘,百度会将共享登录状态的 Cookie 写入到了 .baidu.com域名之下,然后我们刷新百度知道,网站变成了已登录状态,便能在发出的第一个请求中查看到携带了 .baidu.com域名下的 Cookie,百度也已经为我们返回的页面上打印出了用户名。
接下来我们删除这两个 Cookie:BDUSS、BDUSS_BFESS,然后切换到百度网盘并刷新页面,系统显示已经退出。服务器返回 HTTP 响应,通过 Set-Cookie Header 将 .baidu.com下的两个 Cookie 删除,浏览器删除 Cookie 后,同域下的其他网站也就单点退出了。
单点登录机制已成为企业身份及访问管理解决方案中不可或缺的组成部分。同域下的单点登录,是单点登录机制方面的一种常见的解决方案。下期,我们再聊聊跨域下的单点登录,以及更多全方位的身份和访问管理解决方案,请持续关注 Authing。