最近给本身列了一个list,Ummm...列来列去大概是下面这个样子:前端
好吧,谁让本身菜呢,没什么好抱怨的,一个一个来吧。正好最近看了一些token作身份认证的文章,发现其中大部分都是说token登陆怎么怎么好,反正没有几个认认真真的实现的。。。正好,秉着我是小白我怕谁的原则,继续分享一下express + jwt的填坑经历。为何题目起名是最轻实践呢?由于确实看完这个你能够大概理解token登陆的好处以及如何简单的实现一个先后端经过token进行认证的小系统。这个demo是在我第一篇文章那个脚手架上跑起来的,感兴趣的还能够回顾一下----->express-react-scaffold。具体实现就是下面这个样子:react
在先后端分离的系统中,身份认证是十分重要的,目前经常使用的两种身份认证方式以下:ios
JWT的本质实际上就是一个字符串,它有三部分组成头部+载荷+签名。git
// Header
{
"alg": "HS256",//所使用的签名算法
"typ": "JWT"
}
// Payload
{
//该JWT的签发者
"iss": "luffy",
// 这个JWT是何时签发的
"iat":1441593502,
//何时过时,这是一个时间戳
"exp": 1441594722,
// 接收JWT的一方
"aud":"www.youdao.com",
// JWT所面向的用户
"sub":"any@126.com",
// 上面是JWT标准定义的一些字段,除此以外还能够私人定义一些字段
"form_user": "fsdfds"
}
// Signature 签名
将上面两个对象进行base64编码以后用.进行链接,而后经过HS256算法进行加密就造成了签名,通常须要加上咱们提供的一个密匙,例如secretKey:'name_luffy'
const base64url = require('base64url')
const base64header = base64url(JSON.stringify(header));
const base64payload = base64url(JSON.stringify(payload));
const secretKey = 'name_luffy';
const signature = HS256(`${base64header}.${base64payload}`,secretKey);
// JWT
// 最后就造成了咱们所须要的JWT:
const JWT = base64header + "." + base64payload + "." + signature;
// 它长下面这个样子:
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
复制代码
我从官网JWT.io拿下来的图来展现,就是下面这个过程,说的很详细,此外还有一些细节的东西,好比什么形式存储,放在头部哪里,客户端要存储在哪里等,官网都有比较详细的介绍,你们能够去看看。 github
接下来要详细的说如何使用jwt来进行先后端的身份验证了,具体思路以下:web
yarn add express-jwt jsonwebtoken
复制代码
以后就是在登陆环节生成token而且把token返回给前端算法
// /routes/user.js
if (user !== null) {
// 用户登陆成功事后生成token返给前端
let token = jwt.sign(tokenObj, secretKey, {
expiresIn : 60 * 60 * 24 // 受权时效24小时
});
res.json({
success: true,
message: 'success',
token: token
});
}
复制代码
其次,设置拦截token的中间件,包括token的验证以及错误信息的返回:数据库
// jwt.js,token中间件
const expressJwt = require("express-jwt");
const { secretKey } = require('../constant/constant');
// express-jwt中间件帮咱们自动作了token的验证以及错误处理,因此通常状况下咱们按照格式书写就没问题,其中unless放的就是你想要不检验token的api。
const jwtAuth = expressJwt({secret: secretKey}).unless({path: ["/api/user/login", "/api/user/register"]});
module.exports = jwtAuth;
复制代码
// constant.js
// 设置了密码盐值以及token的secretKey
const crypto = require('crypto');
module.exports = {
MD5_SUFFIX: 'luffyZhou我是一个固定长度的盐值',
md5: (pwd) => {
let md5 = crypto.createHash('md5');
return md5.update(pwd).digest('hex');
},
secretKey: 'luffy_1993711_26_jwttoken'
};
复制代码
最后在路由中间件前面放上jwt中间件express
// routes/index.js
// 全部请求过来都会进行身份验证
router.use(jwtAuth);
// 路由中间件
router.use((req, res, next) => {
// 任何路由信息都会执行这里面的语句
console.log('this is a api request!');
// 把它交给下一个中间件,注意中间件的注册顺序是按序执行
next();
});
复制代码
后端逻辑部分所有完成,下面是前端的实现部分。json
第1、把登录成功以后返回的token存在客户端,可使用localStorage也可使用cookie,我看官方推荐使用localStorage,我这边也就用localStorage吧。 第2、每次请求把token放到header头部Authorization字段。
// axios拦截器
// 拦截请求,给全部的请求都带上token
axios.interceptors.request.use(request => {
const luffy_jwt_token = window.localStorage.getItem('luffy_jwt_token');
if (luffy_jwt_token) {
// 此处有坑,下方记录
request.headers['Authorization'] =`Bearer ${luffy_jwt_token}`;
}
return request;
});
// 拦截响应,遇到token不合法则报错
axios.interceptors.response.use(
response => {
if (response.data.token) {
console.log('token:', response.data.token);
window.localStorage.setItem('luffy_jwt_token', response.data.token);
}
return response;
},
error => {
const errRes = error.response;
if (errRes.status === 401) {
window.localStorage.removeItem('luffy_jwt_token');
swal('Auth Error!', `${errRes.data.error.message}, please login!`, 'error')
.then(() => {
history.push('/login');
});
}
return Promise.reject(error.message); // 返回接口返回的错误信息
});
复制代码
此处有坑,在此记录request.headers['Authorization']必须经过此种形式设置Authorization,不然后端即便收到字段也会出现问题,返回401,request.headers.Authorization或request.headers.authorization能够设置成功,浏览器查看也没有任何问题,可是在后端会报401而且后端一概只能拿到小写的,也就是res.headers.authorization,后端用大写获取会报undefined.
很是简单的一个小栗子,也没什么技术含量的文章,就当写着玩练习文笔了。代码没有另外放在哪?就在express-react-scaffold上增长的登陆注册和token认证。能够经过/login来访问登录部分逻辑以及token验证功能。 O(∩_∩)O哈哈~