什么是单点登录?
- 单点登录(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登录/验证流程:
- 浏览器登录发送账号密码,服务端查用户库,校验用户
- 服务端把用户登录状态存为 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实现基本流程:
- 客户端使用账号密码请求登录
- 服务端收到请求,校验账号密码,验证成功,获得用户数据
- 服务端签发一个token(用户信息、token 配置等编码而成)给到客户端
- token通过cookie set到客户端
- 客户端存储token(Cookie 或者 Local Storage)
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
- 服务端收到请求,校验 token
- 检验成功,进行正常业务接口处理,向客户端返回请求的数据
token编码方式
- Base64
Base64
只是一种编码方式,通常配合加密算法一起使用。使用加密算法得到的都是字节数组,使用Base64
对字节数组进行编码就会得到易读的字符串。
- 加签
考虑到token的安全性,为避免token被篡改,需要对token进行加签处理。
对用户信息和密钥进行加密,生成一个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 过期了,那只能重新登陆了。长有效期。
用户登录请求流程分析:
总结
- 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。
- 比如,请求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)。
- 用户进入 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 等方式都是有域限制的。
- 在 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的合法性,验证通过后,允许客户端访问服务。