express使用JWT和httpOnly cookie进行身份验证
对大创项目中使用JWT作为身份验证的总结。
一般情况使用JWT作为身份验证的方式可以直接参考这篇文章:Node.js 使用 express-jwt 解析 JWT 。这里主要针对httpOnly类型的cookie进行代码调整。
1. 安装和引入
需要使用的模块:express-jwt
,用于解析token; jsonwebtoken
,用于生成token ; cookie-parser
,用于解析cookie(据说express已经内置,但是为可能没有该模块导致避免取不到cookie,安装该模块)。
npm i express-jwt jsonwebtoken cookie-parser --save
引入:
const express = require('express');
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const cookieParser = require('cookie-parser');
const app = express();
2. 生成token,放入cookie,验证token
封装一个生成token的方法:
//设置一个私钥
const scrict = 'examplev8w9egf';
function createToken = palyload =>{
//给palyload添加一个生成时间戳的属性
palyload.curtime = Date.now();
//这里添加Bearer是因为express-jwt模块默认获取到token的方法
//当然这里也没必要添加,因为后续我们不会使用默认的解析方式
const token = 'Bearer ' + jwt.sign(
palyload,
scrict, {
expiresIn: 3600 * 24 * 3 //过期时间
})
return token;
}
在需要的位置生成和发送token到cookie:
如果不知道express中怎么使用cookie,可以参考:Express Cookie的使用
app.use('/',(req,res)=>{
let token = createToken({login:true,name:user}) //这里的palyload参数可以自行设定
//将token存入cookie,设置最大失效时间和httpOnly
res.cookie('token',token,{ maxAge:1000*3600*24, path:'/', httpOnly:true });
//响应客户端
res.send({msg:'cookie设置成功'});
}
客户端携带cookie请求:
//这里使用JQ封装的ajax。默认是会自动携带cookie的,无需单独设置:
$.ajax({
//一般情况携带token的方式。但这里设置的是httpOnly类型,使用js是无法获取的,交给服务端处理
/* headers:{
Accept: "application/json; charset=utf-8",
Authorization:token
}, */
url: '/',
type: 'put',
contentType: "application/json",
success: function (data) {
return;
},
error: function (err) {
console.log(err);
},
//这里加一个服务器端校验token失败返回401状态码的操作,跳转回登录界面
statusCode:{
401:function () {
//token验证失败 异常处理
alert('token验证失败!');
}
}
})
服务器端解析cookie中的token:
//cookie-parser挂载
home.use(cookieParser());
//express-jwt挂载,验证token
home.use(expressJwt({
secret:scrict, //封装生成token方法时候设置的私钥
algorithms: ['HS256'], //解码方式建议加上,否则可能会报错
/*重要的是这里,需要改变express-jwt默认取得token的方式
默认模块会从请求头的authorization中取得token,token以'Bearer'开头 */
getToken:function fromCookie(req){
//尝试从cookie读取token进行验证
if(req.cookies.token)
return req.cookies.token.split(' ')[1];
return null;
}
}).unless({
path:['/login','logout'] //白名单,该地址下的不会进行解析
}))
//token校验错误处理中间件
home.use(function (err, req, res, next) {
if (err.name === 'UnauthorizedError') {
console.log(err);
res.status(401).send('invalid token...'); //根据具体情况设置
}
})
//通过解析后的处理
app.use('/user',(req,res)=>{
res.send({err:0,msg:'token通过解析验证'})
})