SSO 的概念

单点登录(Single Sign-On,SSO)是指在多个相关但独立的系统中,用户只需登录一次,就可以访问所有相互信任的系统资源,而无需再次输入用户名和密码等凭证。

例如访问在网易账号中心( http://reg.163.com/ )登录之后访问以下站点都是登录状态

SSO 的简单实现模式

用户登录:用户访问客户端系统,若未登录,则重定向到认证服务器的登录页面。用户输入用户名和密码进行登录,认证服务器验证用户身份后,为用户生成一个唯一的令牌(Token),并将用户重定向回客户端系统,同时携带令牌。

资源访问:客户端系统收到令牌后,将其存储在本地,并在后续的请求中携带令牌访问受保护的资源。被访问的系统接受到请求之后,会将 Token 送到认证系统进行校验,检查合法性。认证服务器验证 Token 的有效性,若有效,则允许客户端系统访问资源;否则,返回错误信息。

单点注销:用户在某个客户端系统中点击注销按钮,客户端系统向认证服务器发送注销请求,认证服务器清除用户的登录状态和令牌,并通知其他相关系统进行注销操作,然后将用户重定向到登录页面。

b219ebc4b74543a97553362c10178a82b8011482 |500

SSO 设计与实现

模块设计

SSO 系统包含几个部分:

  • 任意前端系统:如网易直播、网易博客。
  • 单点登录系统:
    • 前端模块:提供登录、登出。
    • 服务端模块:提供登录、登出、登录状态管理。
    • 存储模块:DB 存储用户账户信息,缓存存储用户登录状态。

用户登录状态的存储与校验

常见的 Web 框架对于 Session 的实现都是生成一个 SessionId 存储在浏览器 Cookie 中。然后将 Session 内容存储在服务器端内存中。

用户登录成功之后,生成 AuthToken 交给客户端保存。如果是浏览器,就保存在 Cookie 中。如果是手机 App 就保存在 App 本地缓存中。本篇主要探讨基于 Web 站点的 SSO。

用户在浏览需要登录的页面时,客户端将 AuthToken 提交给 SSO 服务校验登录状态/获取用户登录信息。

对于登录信息的存储,建议采用 Redis,使用 Redis 集群来存储登录信息,既可以保证高可用,又可以线性扩充。同时也可以让 SSO 服务满足负载均衡/可伸缩的需求。

对象说明
AuthToken直接使用 UUID/GUID 即可,如果有验证 AuthToken 合法性需求,可以将 UserName+时间戳加密生成,服务端解密之后验证合法性
登录信息通常是将 UserId,UserName 缓存起来

用户登录/登录校验

用户登录时序图

|600

用户登录后 Authtoken 保存在 Cookie 中。 domian=test.com 浏览器会将 domain 设置成 .test.com,这样访问所有 *.test.com 的 web 站点,都会将 Authtoken 携带到服务器端。然后通过 SSO 服务,完成对用户状态的校验/用户登录信息的获取。

用户登录校验时序图

|600

用户登出

用户登出时要做的事情很简单:

  1. 服务端清除缓存(Redis)中的登录状态
  2. 客户端清除存储的 AuthToken

登出时序图

|600

跨域登录、登出

前面提到过,核心思路是客户端存储 AuthToken,服务器端通过 Redis 存储登录信息。由于客户端是将 AuthToken 存储在 Cookie 中的。所以跨域要解决的问题,就是如何解决 Cookie 的跨域读写问题。

解决跨域的核心思路就是:

  • 登录完成之后通过回调的方式,将 AuthToken 传递给主域名之外的站点,该站点自行将 AuthToken 保存在当前域下的 Cookie 中。
  • 登出完成之后通过回调的方式,调用非主域名站点的登出页面,完成设置 Cookie 中的 AuthToken 过期的操作。

跨域登录(主域名已登录)

|600

跨域登录(主域名未登录)

|600

跨域登出

|600

参考链接