JWT 全称为 JSON Web Token 是一种在跨域时验证用户的一种措施。
javascript
首先咱们来回想一下传统 cookie session 的验证流程
html
这样会有一个问题,若是 网站A 和 网站B 都是同一家公司。如今要求,网站A 登录了,网站B 也自动登录,请问怎么实现?
一种是 Session 持久化,写入数据库或者其余持久层(好比 redis),各类服务收到请求后,都向持久层请求数据,这种模式架构清晰,可是工程量大,且万一持久层失效,单点登录就会失效。
一种则是服务器直接放弃存储 session 数据了,直接将信息存在客户端。**JWT **就是这种方案的一个表明
java
JWT 的原理是,服务器认证之后,生成一个 JSON 对象发送给客户端,大概长这样。
node
{
"name": 'cjfff',
"role": "admin",
"ita": "认证时间"
}
复制代码
日后在通讯过程当中,每次客户端请求都带上,以识别身份。
可是为了防止数据被擅改,会加入签名信息(Signature)。
git
实际的 JWT 是图示这个样子。
github
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ
.D7OUQ7tygm9PDjXeroA0w3dV4G0Swcbju0jHkS7Hqww
复制代码
能够看到分为了三个部分web
这里先来个帮助函数
redis
const Base64 = {
encode(str) {
// first we use encodeURIComponent to get percent-encoded UTF-8,
// then we convert the percent encodings into raw bytes which
// can be fed into btoa.
let repMap = {
'=': '',
'+': '-',
'/': '_'
}
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
function toSolidBytes(match, p1) {
return String.fromCharCode('0x' + p1);
})).replace(/(=|\+|\/)/g, (key) => repMap[key])
},
decode(str) {
// Going backwards: from bytestream, to percent-encoding, to original string.
return decodeURIComponent(atob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
};
复制代码
大概以下,里面记录着 type,alg 就是加密算法, 能够看到,加密后是与开头数据结构中的 header(第一部分是相同的).
算法
Base64.encode(JSON.stringify({
"alg": "HS256",
"typ": "JWT"
})) === 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // true
复制代码
能够看到 payload 信息也是产出一致的。
数据库
Base64.encode(JSON.stringify({
"role": "admin",
"name": "cjffff",
"iat": 1516239022
})) === 'eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ'
复制代码
签名的生成规则以下,这里就不作测试了
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
复制代码
JWT 只是为了解决用户会话的问题,大白话就是识别用户身份。
JWT 自己并无进行加密的行为,Signature(签名) 也只是为了别人擅改数据而已,若是数据被抓包,payload(jwt第二部份内容)中若是携带用户敏感信息的话,第三方使用 base64 解密便可得到数据,因此为了安全性而言请使用 https 代替 http。
**
另外就是应该防止加密用的 **secret **泄漏。
安全总结:
**JWT **在签发的时候会为 **payload **加上一个 iat(issued at) 签发时间。
而后客户端下次发送带上发送给服务端的时候会根据服务端的过时策略进行验证
好比,服务端设置的过时时间是 10h
另外就是,若是用户数据被擅改,此时 JWT 应该是属于过时的,但因为 JWT 的机制问题,token 签发后并无相关的废弃策略,只能使用额外的逻辑去对过时的 JWT 进行过时操做,好比将过时的 JWT 维护在 黑名单列表中。
客户端收到服务端返回的 JWT 后,能够存储在 COOKIE 中,也能够存储在 localStorage 中。
当每次发送请求的时候, 在 headers 加上 Authorization 字段,内容为 Bearer ${jwt}
便可
而后服务端会用上述接收到的信息,拿到 header + payload 为输入数据,进行上面算法生成 Signature 再和 客户端接收到的 Signature 进行对比,一致的话就完成了验证。