JWT主要由三部分组成
1.头部header
主要由两部分信息组成
声明类型 JWT
声明加密算法,如:HMAC、SHA256、HS256
下面就是一个完整的头部信息:
{
"typ": "JWT"
"alg": "HS256"
}
Base64进行编码后的字符串如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2.载荷 payload
主要有三部分组成:标准中注册声明、公共的声明、私有声明
标准中组成声明
iss:jwt签发者,是否使用是可选的;
sub:jwt所面向的用户,是否使用是可选的;
aud:接收jwt的一方,是否使用是可选的;
exp:jwt的过期时间,这个过期时间必须大于签发时间,Unix时间戳,是否使用是可选的;
nbf:定义在什么时间之前,该token都是不可用的
iat:jwt的签发时间,是否使用是可选的;
jti:jwt的唯一身份标识,避免重复
如:
{
"iss": 'jwt'
"sub": "h3yun.com",
"exp": "16386018625",
"iat": "1638605625",
"jti": "e983544312y4343432143rweqrr",
}
Base64 编码后字符串如下
JTdCJTBBJTIwJTIwJTIyaXNzJTIyJTNBJTIwJTI3and0JTI3JTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyaDN5dW4uY29tJTIyJTJDJTBBJTIwJTIwJTIyZXhwJTIyJTNBJTIwJTIyMTYzODYwMTg2MjUlMjIlMkMlMEElMjAlMjAlMjJpYXQlMjIlM0ElMjAlMjIxNjM4NjA1NjI1JTJDJTBBJTIwJTIwJTIyanRpJTIyJTNBJTIwJTIyZTk4MzU0NDMxMnk0MzQzNDMyMTQzcndlcXJyJTIyJTJDJTBBJTdEJTBB
3.签名 signature
讲上面 header 和 payload base64编码之后的拼接起来 :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.JTdCJTBBJTIwJTIwJTIyaXNzJTIyJTNBJTIwJTI3and0JTI3JTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyaDN5dW4uY29tJTIyJTJDJTBBJTIwJTIwJTIyZXhwJTIyJTNBJTIwJTIyMTYzODYwMTg2MjUlMjIlMkMlMEElMjAlMjAlMjJpYXQlMjIlM0ElMjAlMjIxNjM4NjA1NjI1JTJDJTBBJTIwJTIwJTIyanRpJTIyJTNBJTIwJTIyZTk4MzU0NDMxMnk0MzQzNDMyMTQzcndlcXJyJTIyJTJDJTBBJTdEJTBB
以 HS256 为例
signature = HS256( 上面拼接起来的字符串. xxxx); // xxx 表示 一串随机的字符
最后 把上面三部分连接起来就是我们需要的JWT Token了
整个校验流程是:
1. 用户在登录页,输入用户名和密码,进行登录
2. 服务器对登录用户进行认证,如果认证通过,根据用户的信息和JWT的生成规则生成JWT Token
3. 服务器将该Token字符串返回
4. 客户端得到Token信息,将Token存储在cookie中。
5. 当用户请求服务器API时,在请求的Header中加入 Authorization:Token。
6. 服务端对此Token进行校验,如果合法就解析其中内容,根据其拥有的权限和自己的业务逻辑给出响应结果,如果不通过,返回HTTP 401,提示用户权限。通过就执行前端回调进入系统
前端请求是将 token 放入到header里边 Authorization
第一种:
proxy.js 文件
const proxyAjax = () => {
if (!XMLHttpRequest) {
return;
}
const nativeAjaxSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (...args) {
const oldCb = this.onreadystatechange;
const token = getToken();
if (token) {
this.setRequestHeader('authorization', `Bearer ${token}`);
}
this.onreadystatechange = (...innerArgs) => {
if (this.readyState === 4) {
switch (this.status) {
case 401:
// token 失效, 清除cookie中token, 跳转到登录页
clearAuthorization(); //自己实现清除方法,这里不展开
//to do
break;
default
break;
}
}
oldCb && oldCb.apply(this, innerArgs);
};
return nativeAjaxSend.apply(this, args);
};
};
export default proxyAjax();
在项目中入口文件引入即可,如果是vue 多页面就每个页面main.js都需要引入
第二种:
如果是项目中引入请求的 axios 或fetch 改,以axios为例
axios.interceptors.request.use((config) => {
config.headers.authorization=`Bearer ${token}`;
……
}, error => {
Promise.reject(error);
});
第三种: 每一个接口去设置 Authorization
fetch('xxx', { //接口地址
headers: {
'Authorization': 'Bearer ' + token
}
})
显然不如上面好
JWT Token机制优缺点
优点:
不需要储存在服务器的session中,更容易扩展服务器
由于用户信息可以放入token中,所以可以少了一次数据库 / 缓存的查询操作,有更好的性能
不需要预防CSRF的攻击
缺点:
token一经泄露或者被盗取,将会暴露该用户
建议
设置token的过期时效时间,不宜过长; 协议使用https
安全较高的接口,二次验证保险 如手机验证码,支付密码等