express中实现加密JWT(JSON Web Token)
JWT(JSON Web Token)
JWT(json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。(json格式传token)
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。
JWT数据结构
JWT的三个部分:JWT头、有效载荷和签名。
JWT头
JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。
{
“alg”: “HS256”,
“typ”: “JWT”
}
上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。
有效荷载
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
除此之外,你还可以自定义字段,如:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
签名
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
JWT工作过程
工作过程:
1.前端向服务端发送用户名和密码。
2.服务端生成JWT。
3.将生成的JWT发送到前端,相关数据(如用户角色,登录时间等)将保存在当前会话中。
4.前端向服务端请求数据时,将JWT放到Header中,发送给服务端。
5.服务端收到JWT,进行验证,确认用户信息。
6.验证成功,返回数据给前端。
express实现过程
express部分
1、下载express-jwt (生成 token)+ jsonwebtoken(验证 token)两个包
2、设置了密码盐值以及token的secretKey(JWT默认是不加密的,这里用到了MD5加密,并用salt对密码进行了复杂化)
// /constant.js
var crypto = require('crypto');
module.exports = {
MD5_SUFFIX: 'houyuping', //固定长度的盐值salt
md5: function (pwd) {
var md5 = crypto.createHash('md5');
return md5.update(pwd).digest('hex');
},
secretKey: 'yichen_qingting_jwttoken'
};
3、在登录环节生成token
// /routes/user.js
var token = jwt.sign(data, constant.secretKey, {
expiresIn: 60 * 60 * 24 // 授权时效24小时
})
res.json({
success: true,
message: 'success',
token: token
})
4、设置拦截token的中间件,包括token的验证以及错误信息的返回:
// /jwt.js
const expressJwt = require("express-jwt");
const secretKey = require('./constant');
// express-jwt中间件帮我们自动做了token的验证以及错误处理,所以一般情况下我们按照格式书写就没问题,其中unless放的就是你想要不检验token的api。
const jwtAuth = expressJwt({secret: secretKey.secretKey}).unless({path: ["/users/login","/users/query"]});
module.exports = jwtAuth;
5、最后在路由中间件前面放上jwt中间件
var express = require('express');
var router = express.Router();
var jwtAuth = require('./jwt')
// 所有请求过来都会进行身份验证
router.use(jwtAuth);
// 路由中间件
router.use(function (req, res, next) {
// 任何路由信息都会执行这里面的语句
console.log('this is a api request!');
// 把它交给下一个中间件,注意中间件的注册顺序是按序执行
next();
});
前端部分
1、将获取的token保存到localstorage中
let token = window.localStorage.getItem("wyg_token");
2、每次请求带上token,将token放入header中
this.$axios.post('http://127.0.0.1:3000/users/modifyPwd',
{data: data},
{headers: {'Authorization': `Bearer ${token}`}}
)
JWT优缺点
优点:
1. 不易被攻击,安全性高
2. 利用Authorization首部传输token,无跨域问题
3. 额外信息存储在客户端,服务端占用资源不多,也不存在session共享问题
缺点:
1. 登录状态信息续签问题。一旦发放令牌,在过期时间内无法修改注销。
2. 占用内存比cookies要大。