前言
之前在做SSO的时候选择了JWT这个技术,一直没时间去系统的学习这个技术,本文做一个学习笔记提供给后来的自己看看。
基本概念
JWT是json web tokens的简称,是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准。JWT的声明一般被用来在身份提供者和服务这之间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
原理
由于http协议本身是一种无状态的协议,当用户使用账户和密码进行用户认证完成后并不能存在登录状态,导致下次请求依旧需要再次认证。因为服务器仅仅通过http协议,并不能知道是哪个用户发出的请求,所以需要借助一些处理机制来记录认证状态,从而完成请求和相应。
session认证
session认证是将用户的认证信息存储在服务器端,并且会在认证通过后将这一份认证信息传递给浏览器端,浏览器将其保存为cookie。浏览器在下次发送请求时会将该cookie携带并且发送给服务器,这样应用就能识别请求来自哪个用户。
由于session认证的应用本身很难扩展,随着不同客户端用户的增加,独立的服务器无法承载越来越多的用户。常见问题如下:
- session:由于每个用户经过认证服务器认证后,都在在认证服务器端做一次记录,通常该记录保存在内存中,导致内存占用率随着认证用户数量的增加而越来二大,服务的开销也会越来越大。
- 扩展性:用户认证之后,服务器端将认证记录存储在内存中,这就意味着该用户的下次请求必须在这台服务器上,只有这样授权才能通过。这种方式下限制了负载均衡其的能力。也就限制了应用的扩展能力。
- CSRF(跨站请求伪造):因为基于cookie来进行用户识别,所以当cookie被劫持,用户就很容易受到跨站请求伪造的攻击。
token认证
token的身份认证是无状态的,不将用户信息存储在服务器中,原理是:
- 用户通过用户名和密码发送请求
- 服务器端程序验证用户名和密码
- 验证成功后服务器端程序会返回一个带签名的token给客户端
- 客户端存储token,并且每次访问API都携带token到服务器端
- 服务器端验证token,校验成功则返回请求数据,校验失败则返回错误码
其特点如下:
- 无状态、可扩展
在客户端存储的token是无状态的,并且能够被扩展,基于这种无状态和不存储session信息,负载均衡器能够将用户信息从一个服务器传到其他服务器上。
- 安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制,而不是用于认证。token是有时效的,一段时间之后用户需要重新验证。
- 扩展性
token能够创建与其他程序共享权限的程序。
- 多平台跨域
跨域资源共享
JWT结构
JWT由头部(header)、载荷(payload)和签名(signature)构成,header.payload.signature,三个部分通过.分割。类似:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFO
- 头部(header)
JWT的头部分是一个json对象,描述元数据,通常是:
{
"typ": "JWT", // 声明类型,这里是JWT
"alg": "HS256" // alg是加密算法,默认是HS256
}
- 载荷(payload)
数据的载体,用来存放实际需要传递的数据信息,也是一个json对象。可以使用定义的字段,也可以使用官方推荐字段:
- iss:jwt签发者
- sub:jwt所面向的用户
- aud:接受jwt的一方
- exp:jwt的过期时间,这个过期时间必须大于签发时间
- nbf:定义在什么时间之前,该jwt都是不可用的
- iat:jwt的签发时间
- jti:jwt的唯一身份标准,主要用来作为一次性token,从而回避重放共计。
- 签名(signature)
签名是对前两步法的签名,仿制数据篡改。按照下列步骤生成:
- 先指定密钥(secret)
- 把头部和载荷信息分别base64转换
- 使用头部指定的算法加密
最终:签名(signature) = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)。
JWT的使用原理:
- 服务端根据用户登录状态将用户信息加密到token中,返回给客户端
- 客户端收到服务端返回的token,存储在cookie中
- 客户端和服务端每次通信带上token,可以放在http请求头信息中,如:Authorization字段里面
- 服务端解密token,验证内存,完成相应逻辑
JWT特点
- 简洁,适合在html和http环境中传递
- 适合一次性验证,如:激活邮件
- 适合无状态验认证
- 适合服务端CDN分发内容
- 相对于数据库session查询省时
- 使用期间不可取消token或更改token权限
- 建议使用https协议来传输代码