单点登录方案调研

2,449 阅读9分钟

什么是单点登录?

  • 单点登录(Single Sign On, SSO)是指在同一帐号平台下的在多系统应用群中,用户只需登录一次,或者说登录一个系统,即可访问所有相互信任的应用系统。其本质就是在多个应用系统中共享登录状态。
  • 单点登录是一种架构,一种思想。

什么是认证、授权、凭证?

认证(Authentication)

验证当前用户的身份,互联网中的认证场景:

  • 用户名密码登录
  • 邮箱发送登录链接
  • 手机号接收验证码
  • 收到邮箱/验证码,默认是账号的主人

授权(Authorization)

  • 用户授予第三方应用访问该用户某些资源的权限
  • 授权实现的方式:cookie、session、token、OAuth

凭证(Credentials)

实现认证和授权的前提是需要一种媒介(证书)  来标记访问者的身份。

当用户登录成功后,在登录模式下,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌,就可以使用游客模式下无法使用的功能。

早期的多系统单点登录解决方案

一、cookie:是大多数单点登陆实现登录状态管理的基石

cookie 是一种完善的状态标记方式,借助Http head、浏览器能力,前端实现无感知储存。

背景相关补充:http是一个无状态协议 无状态就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的。但现在是希望几个请求的页面要有关联,比如:我已经登陆过了淘宝,我在天猫首页也希望是登陆状态。这是2个不同的页面,也就是2个不同的HTTP请求,这2个HTTP请求是无状态的,也就是无关联的。

二、session-cookie

session是一次浏览器和服务器的交互的会话。

典型session登录/验证流程:

image.png

  • 浏览器登录发送账号密码,服务端查用户库,校验用户
  • 服务端把用户登录状态存为 Session,生成一个 sessionId
  • 通过登录接口返回,把 sessionId set 到 cookie 上
  • 此后浏览器再请求业务接口,sessionId 随 cookie 带上
  • 服务端查 sessionId 校验 session,如果存在,则视为已登录
  • 成功后正常做业务处理,返回结果 补充

cookie只是实现session的其中一种方案。虽然是最常用的,但并不是唯一的方法。禁用cookie后还有其他方法存储,比如放在url中。

分布式环境和微服务系统中-Session不共享问题解决方案

session是由容器产生和管理的。用Session保存用户信息来实现单点登录,在多服务器(分布式、负载均衡)场景下,存在Session不共享问题,因此不好确认当前用户是否登录。

1、基于Nginx的ip_hash负载均衡

  • 根据自己的可用服务器,配置 ip_hash。根据请求的IP进行Hash映射到对应的机器上,相同 IP 的请求在负载均衡时都打到同一台机器上;
  • session直接存jvm内存,服务端重启,会导致session失效。如果服务器宕机了,会丢失了一大部分Session的数据。

2、Session全局复制

利用Tomcat集群节点广播复制机制,集群内每个tomcat的session完全同步;集群性能会受到影响。

3、redis集中存储session

因为session是存在有效期的,所以可以在Redis中设置与之对相应的有效时间

三、token(令牌)

token就是将一个登录场景的轻量登录信息直接打包到cookie。

token实现基本流程:

image.png

  • 客户端使用账号密码请求登录
  • 服务端收到请求,校验账号密码,验证成功,获得用户数据
  • 服务端签发一个token(用户信息、token 配置等编码而成)给到客户端
  • token通过cookie set到客户端
  • 客户端存储token(Cookie 或者 Local Storage)
  • 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
  • 服务端收到请求,校验 token
  • 检验成功,进行正常业务接口处理,向客户端返回请求的数据

token编码方式

  • Base64

Base64只是一种编码方式,通常配合加密算法一起使用。使用加密算法得到的都是字节数组,使用Base64对字节数组进行编码就会得到易读的字符串。

  • 加签 考虑到token的安全性,为避免token被篡改,需要对token进行加签处理。 企业微信截图_16431048267400.png 对用户信息和密钥进行加密,生成一个token签名,把这个原始token(用户数据)和签名一起作为 token。客户端把 token 发过来的时候,再用同样的 HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名,和 token 中的签名做比较。签名相同,则可以知道用户已经登录,并得到用户信息。如果不相同,原始token部分肯定被人篡改过,就可以告诉发送者,用户登录状态认证失败。

常见加密算法:

  • 消息摘要算法: MD、SHA、 MAC...
    消息摘要算法适合作为数字签名算法
  • 对称加密算法:AES、DES
  • 非对称加密算法:RSA
  • 国密算法

以JWT来举例:

JSON Web Token (JWT) 是一个开放标准,定义了一种传递 JSON 信息的方式。这些信息通过数字签名确保可信。

refresh token与access token

  • access token: 业务接口用来鉴权的 token,我们称之为 access token。越是权限敏感的业务,我们越希望 access token 有效期足够短,以避免被盗用。但过短的有效期会造成 access token 经常过期。
  • refresh token:用来生成access token的token。如果refresh token 过期了,那只能重新登陆了。长有效期。

用户登录请求流程分析:

image.png

总结

  • session 和 token 的对比就是「用不用cookie」和「后端存不存」的对比。
  • session 是「种在 cookie 上、数据存在服务端」的认证方案。
  • token 是「客户端存哪都行(localStorage,cookie,或sessionStorage...)、数据存在 token 里」的认证方案;服务端就不用存数据,核验cookie带有的有效信息即可。

同域下的"单点登录"是非严格意义上来说的单点登录,也就是"伪"单点登录。

为什么需要单点登录

一、(同域名)共享cookie的方式存在局限性

1、cookie本身是不可跨域的

  • Cookie 的作用域由 domain 属性和 path 属性共同决定。

domain 属性的有效值为当前域或其父域的域名/IP地址。path 属性的有效值是以“/”开头的路径,path 属性默认为当前 Web 应用的上下文路径。

  • 如果将 Cookie 的 domain 属性设置为当前域的父域,那么就认为它是父域 Cookie。Cookie 有一个特点,即父域中的 Cookie 被子域所共享,换言之,子域会自动继承父域中的Cookie。 企业微信截图_16426692554279.png
  • 比如,请求wenku.baidu.com 的时候,浏览器会自动把baidu.com的Cookie带过去给wenku.baidu.com的服务器。这就意味着,由于域名不同,用户向系统A登录后,系统A返回给浏览器的Cookie,用户再请求系统B的时候不会将系统A的Cookie带过去。

2、服务端技术选型要求

应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间。

3、cookie本身不安全

cookie存储在浏览器端(用户本地)

真正的单点登录

  • 把SSO看作是一个单独的认证服务。不处理业务逻辑,只是做用户信息的管理以及授权给第三方应用。
  • 单点登录要求不同域下的系统「一次登录,全线通用」,通常由独立的 SSO 系统记录登录状态、下发登录凭证ticket(token),各业务系统配合存储认证 ticket(token)。 image.png
  • 用户进入 A 系统,没有登录凭证(ticket),A 系统给他跳到 SSO
  • SSO 没登录过,也就没有 sso 系统下没有凭证(注意这个和前面 A ticket 是两回事),输入账号密码登录
  • SSO 账号密码验证成功,通过接口返回做两件事:一是种下 sso 系统下凭证(记录用户在 SSO 登录状态);二是下发一个 ticket
  • 客户端拿到 ticket,保存起来,带着请求系统 A 接口
  • 系统 A 校验 ticket,成功后正常处理业务请求
  • 此时用户第一次进入系统 B,没有登录凭证(ticket),B 系统给他跳到 SSO
  • SSO 登录过,系统下有凭证,不用再次登录,只需要下发 ticket
  • 客户端拿到 ticket,保存起来,带着请求系统 B 接口 对浏览器来说,SSO 域下返回的数据要怎么存,才能在访问 A 的时候带上?浏览器对跨域有严格限制,cookie、localStorage 等方式都是有域限制的。 image.png
  • 在 SSO 域下,SSO 不是通过接口把 ticket 直接返回,而是通过一个带 code 的 URL 重定向到系统 A 的接口上,这个接口通常在 A 向 SSO 注册时约定
  • 浏览器被重定向到 A 域下,带着 code 访问了 A 的 callback 接口,callback 接口通过 code 换取 ticket
  • 这个 code 不同于 ticket,code 是一次性的,暴露在 URL 中,只为了传一下换 ticket,换完就失效
  • callback 接口拿到 ticket 后,在自己的域下 set cookie 成功
  • 在后续请求中,只需要把 cookie 中的 ticket 解析出来,去 SSO 验证就好
  • 访问 B 系统也是一样

开源认证服务

CAS(Central Authentication Service)

单点登录主要访问流程:

  • 访问服务:SSO客户端发送请求访问应用系统提供的服务资源。
  • 定向认证:SSO客户端会重定向用户请求到SSO服务器。
  • 用户认证:用户身份认证。
  • 发放票据:SSO服务器会产生一个随机的Service Ticket。
  • 验证票据:SSO服务器验证票据Service Ticket的合法性,验证通过后,允许客户端访问服务。

XXL-SSO

github.com/xuxueli/xxl…