基本思路
- 用户登录校验成功后服务端会根据 用户信息和时间 生成token,并将其和用户的信息一起发送给客户端。
- 客户端将token存到localStorage,将用户的信息挂载到vue实例下,每次发送请求或进行操作可以通过用户信息判断其是否有权限。
- 客户端每次发送请求都将token携带在请求头中传给服务端。
- 服务端每次接收请求验证token的有效性和时间是否过期,如无法验证通过,返回错误的信息给客户端。
- 客户端接收token无效的信息重新跳到登录页面,用户重新登录。
功能实现
yarn add jsonwebtoken
前端部分
- 登录获取token
this.$axios.post("/api/login/user", {
userName: this.userName,
password: this.password
}).then(res => {
if (res.code == 0) {
this.$router.push({
name: "homepage"
});
//vm为window下的vue实例对象,用户可以在组件中通过vm.$user或this.$root.$user获取用户的信息控制其权限。
vm.$user = res.data.user;
localStorage.setItem('token',res.data.token)
} else {
this.$messageTips(res.msg, "warning", 2000);
this.load = false;
this.state = "登录";
}
});
- axios请求登录拦截
// 处理请求拦截
instance.interceptors.request.use(
config => {
config.headers.Token = localStorage.getItem('token')||''
return config
}
)
// 处理响应拦截
instance.interceptors.response.use(
response => {
if(response.data.msg=='token无效') {
vm.$messageTips(response.data.msg, "warning", 2000)
vm.$router.push({
name: "login"
});
}
return response.data
},
)
后端部分
- 登录部分
var express = require('express');
var router = express.Router();
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://127.0.0.1:27017/';
var jwt = require('jsonwebtoken')
var {secret} = require('../config')
router.post('/user', function (req, res) {
var userName = req.body.userName;
var password = req.body.password;
MongoClient.connect(url, {
useNewUrlParser: true
}, function (err, client) {
if (err) {
console.log('连接失败', err);
res.json({
code: 1,
msg: '网络异常, 请稍候重试'
})
return;
}
var db = client.db('myBlog');
console.log(userName);
console.log(password);
db.collection('user').find({
userName: userName,
password: password
}).toArray(function (err, data) {
if (err) {
console.log('查询失败', err);
res.json({
code: 1,
msg: '网络异常, 请稍候重试'
})
} else if (data.length <= 0) {
res.json({
code: 1,
msg: '用户名或密码错误'
})
} else {
//secret是我们单独保存在config里面的一个密钥,用来生成token和解密token,expiresIn是过期时间,单位秒。
var token = jwt.sign({
data: String(data[0]._id),
}, secret, {
expiresIn: 24*3600
})
res.json({
code: 0,
msg: '登录成功',
data: {
user: data[0],
token
}
})
}
client.close();
})
})
});
module.exports = router;
- 拦截部分
使用中间件拦截接口,除登录外的接口都验证token的有效性。
var express = require('express');
var app = express();
var jwt = require('jsonwebtoken')
var {secret} = require('./config')
// 引入路由模块
var LoginRouter = require('./routes/login.js')
// 使用路由模块,中间件
app.all("*", function (req, res, next) {
var token = req.headers.token
jwt.verify(token, secret, function (error, data) {
if (error && req.path != '/api/login/user') {
console.log(error.message); // 验证不通过
return res.json({
code: 1,
msg: 'token无效'
})
}
console.log(data);
next()
})
})
app.use('/api/login/', LoginRouter);
let server = app.listen(3000);