前言
互联网服务离不身份验证,JWT一种跨域身份验证解决方案,全称JSON WEB TOKEN,在web中通过json格式组装数据传输的一种token。
JWT的特点
- 无状态(token签发后服务器不会保留任何用户登录信息)
- 可扩展 (token仅存储在客户端完全无状态,因此可以负载均衡传输到任何服务器)
- 通用性 (jwt是一串加密的字符,只要能转输字符就能使用jwt)
JWT对比SESSION
session的工作方式
- 前端输入用户名密码通过http请求发送给服务器
- 服务器验证通过,在服务器本地保存一个session(里面写入了业务数据)
- 服务器返回一个session_id给前端,前端自动写入cookie
- 前端登录成功,下次发请求前端会自动带上有session_id的cookie
- 服务器拿到session_id去本地找到对应的session读取里面的数据
jwt的工作方式
- 前端输入用户名密码通过http请求发送给服务器
- 服务器验证通过,将业务数据(如用户的id,称昵等)通过base64进行编码生成token
- 服务器将token写入http请求响应中返回给前端
- 前端拿到token存储在本地,下次发请求时将token放在http请求中带给服务器
- 服务器收到token通过base64解密拿到业务数据
- 服务器进行签名对比,签名一致证明用户合法
明显的区别jwt存储在客户端,session存储在服务器所以不利于分布式多台服务器负载均衡(因为用户登录后只在一台服务器存储了session别的服务器上没有),需且还会占用服务器存储空间。
还有个硬伤session是依赖cookie传输session_id的,但有些客户端是不支持cookie的比如说小程序。
jwt长什么样?
如图jwt是一串由三个点分隔开的加密字符串,由 header(头部)、payload(负载)、signature(签名)组成。
header
header由一个json对象组成,里面包函两个字段:
{
"alg": "HS256", // 表示token的类型是jwt
"typ": "JWT" // 表示使用的签名算法是HS256
}
将这部分由base64编码组成jwt字符串的第一部分。
payload
payload也是由一个json组成,里面用来存放业务数据通常是用户的基本信息(用户id,用户权限)和一些用来描述令牌的数据(令牌的颁发时间,令牌的过期时间)。
jwt官方推荐了七个字段,但这不是必须的:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
我经常定义这几个字段:
{
"uid": "HS256", // 用户的id
"nickname": "bwx", // 用户的昵称
"exp": "1608703180085" // 令牌的过期时间
}
将这部分由base64编码组成jwt字符串的第二部分。
注意:不要在JWT的payload或header中放置敏感信息,只需存储用户的唯一标识即可,因为payload、header部分只是通过base64将json格式的数据编码成字符串方便传输,客户端拿到这串字符编码回去即可看到里面的内容。
signature
signature是对header和payload进行签名防止数据被篡改。
签名的过程是将base64编码后的header、base64编码后的playload以及密钥secret
通过header中指定的算法进行计算得到。
这个secret不能泄漏只能服务器知道。
因为如果客户端拿到token进行base64解码,然后修改前两部分的数据(header、payload)再用base64编码回去发送给服务端,服务拿到header、payload两部分加上secret加密得到signature,跟客户端传入的signature做对比发现不一致,因此就能得知数据被篡改了。
上图可看到jwt的组织结构。
token的过期时间设置多久好?
-
面对极度敏感的信息,如钱或银行数据,那就根本不要在本地存放Token,只存放在内存中。这样,随着App关闭,Token也就没有了。
-
此外,将Token的时限设置成较短的时间(如1小时)。
-
对于那些虽然敏感但跟钱没关系,如健身App的进度,这个时间可以设置得长一点,如个月。
-
对于像游戏或社交类App,时间可以更长些,半年或1年。
token泄漏别人可以冒充我登录吗?
别人拿到你的token通过http请求发送给服务器是可以冒充你的,但我们可以在服务器写一些逻辑预防这些:
-
在服务器为用户建立一个常用ip表存储用户常用ip,当你的token被盗取防问服务器的ip不再常用ip表中就让用户重新授权,有点类似于QQ的异地登录。
-
颁发令牌时将用用户的ip存储到
jwt
payload中,当你的token被盗取防问服务器的ip跟payload中的ip不一至就让用户重新授权。 -
token过期时间设置的短一些。
参考链接
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html by 阮一峰