Single Sign On(SSO)
单点登录:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。
同域下的单点登录
通过三级域名(app.xxx.com)区分应用,可以设置二级域名下的 cookie,利用三级域名可以访问二级域名的方式,实现 cookie 在不同应用之间的传递。
跨域下的单点登录
使用 CAS 流程实现,该流程是单点登录的标准流程
- 未登录用户访问 app,跳转到 CAS Server (SSO 登录系统)
- SSO 登录认证后,将登录状态写入 SSO 的 session,浏览器端记下 SSO 域的 cookie
- SSO 登录完成后生成一个 Service Ticket,跳转至 app 并传递该数据
- app 获取 Service Ticket 后向后端请求验证是否有效
- app 验证通过后记下 session 并设置 app 域的 cookie
NOTE
- Service Ticket 通常保存在 redis 中
JSON Web Token(JWT)
JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准,适用于分布式站点的 SSO 场景
传统的 session 认证
客户端存储 cookie 用于标识用户,服务端根据 cookie 进行 session 认证;
session 认证的问题
- session 通常存储于内存中,用户的增多会提高服务端的开销
- 由于认证存储于内存中,在分布式的应用上,限制了负载均衡器的能力
- cookie 若被截获容易受到 CSRF 攻击
基于 token 的鉴权机制
工作流程
- 用户登录
- 服务器验证登录信息
- 服务器通过验证发送 token
- 客户端存储 token 并在每次请求时附送上 token
- 服务端验证 token 后进行正常处理流程
该 token 需要保存在请求头中,服务端需要支持 CORS 策略
JWT 组成部分
JWT 是三段用 . 连接的字符串,包括头部、载荷、签名
头部
包括声明类型和声明加密算法,如
json
{
"typ:": "JWT",
"alg": "HS256"
}然后对头部进行 base64 转换生成第一部分字符串
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9载荷
用于存放有效信息,包括
- 标准中注册的声明
- iss: jwt 签发者
- sub: jwt 所面向的用户
- aud: 接收 jwt 的一方
- exp: jwt 的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该 jwt 都是不可用的.
- iat: jwt 的签发时间
- jti: jwt 的唯一身份标识,主要用来作为一次性 token,从而回避重放攻击。
- 公共的声明:可添加任何非敏感信息,该部分可被解密
- 私有的声明:提供者和消费者共同定义的声明,该部分可被解密
然后对头部进行 base64 转换生成第二部分字符串
签名
js
// 生成方式如下
var encodedString = Base64.encode(header) + "." + Base64.encode(payload);
// NOTE: 后端生成,secret 为服务端数据,不能暴露给客户端
var signature = HMACSHA256(encodedString, secret);使用
js
const url = "";
const token = ""; // JWT
fetch(url, {
headers: {
Authorization: "Bearer" + token,
},
});小结
由于 JWT 签名部分在服务端生成,可以避免数据被篡改
头部和载荷部分使用 Base64 转换,可以被解析
JWT 相较于 session 少了缓存机制,在使用中无法废止,通常需要设置一个有效期