最近在app的開發過程中,做了一個基於token的用戶登錄認證,使用vue+node+mongoDB進行的開發,前來總結一下。
token認證流程:
1:用戶輸入用戶名和密碼,進行登錄操作,發送登錄信息到服務器端。
2:服務器端查詢數據庫驗證用戶名密碼是否正確,正確,通過jsonwebtoken生成token,返回給客戶端;否則返回錯誤信息給客戶端。
3:通過本地存儲存儲獲取的token信息,並且會跳轉到路由指定的頁面。
4:當客戶端需要請求數據時,發送請求,並且在請求的頭文件中添加本地存儲的token信息。
5:服務器端獲取到請求頭文件中的token信息,解析token信息,驗證是否有效,有效,查詢數據庫,返回請求的數據。
客戶端與服務器端關於token的驗證示意圖:

1:用戶登錄的模型骨架文件user.js
'use strict';
let mongoose = require('mongoose'),
Schema = mongoose.Schema;
let userSchema = new Schema({
"username": String,
"password": String,
"token": String,
"create_time": Date
});
let users = mongoose.model('users', userSchema);
module.exports = users;
2:服務器端api請求文件api.js
const express = require('express');
const router = express();
const db=require('../db/db.js');
const User=require('../db/user.js');
const Login=require('../db/login.js');
const Fan=require('../db/fan.js');
const Power=require('../db/power.js');
const createToken = require('../token/createToken');
const checkToken = require('../token/checkToken');
// 注冊
router.post('/add', function(req, res, next){
let username = req.body.username,
password = req.body.password;
let newUser = new User({
username: req.body.username,
password: req.body.password
});
User.findOne({"username":username},(err, result) => {
if(err){
console.log('error:' + err);
return;
}
console.log('result:',result);
if(!result){
newUser.save(function(err, result){
if(err){
console.log('error:' + err);
return;
}
res.send({success: true, msg: '注冊成功'});
});
}else{
res.send({success: false, msg: '用戶名已經存在'});
}
});
});
// 登錄
router.post('/login', function(req, res, next){
let username = req.body.username,
password = req.body.password;
User.findOne({"username":username},(err, result) => {
if(err){
res.send({success: false, msg: '用戶名不存在'})
console.log('error:' + err);
return;
}
console.log('result:',result)
if(result.password === password){
console.log('登錄成功')
// 調用token生成函數
let _token = createToken(username);
// 保存token到數據庫中
result.token = _token;
result.save((err) => {
if(err){
console.log('error:' + err + 'token')
}
})
if(result){
res.send({success: true, msg: '登錄成功', token: _token});
}else{
res.send({success: false, msg: '登錄失敗'});
}
}else{
res.send({success: false, msg: '密碼錯誤'});
}
});
});
// token
router.post('/createtoken', function(req, res, next){
let username = req.body.username;
User.findOne({"username":username},(err, result) => {
if(err){
res.send({success: false, msg: '用戶名不存在'})
console.log('error:' + err);
return;
}
console.log('result:',result)
let token = createToken(username);
result.token = token;
result.save((err) => {
if(err){
console.log('error:' + err + 'token')
}
})
if(result){
res.send({success: true, msg: '登錄成功', token: token});
}else{
res.send({success: false, msg: '登錄失敗'});
}
});
});
// 刪除用戶
// 刪除用戶時,驗證token信息是否過期
router.get('/delete', checkToken, function(req, res, next){
let _username = req.body.username;
User.remove({username: _username}, (err, result) => {
if(err){
console.log('error:' + err);
return;
}
res.send(result);
});
});
module.exports = router;
3:服務器端token生成文件createToken.js
const jwt = require('jsonwebtoken');
module.exports = function(user_id){
const token = jwt.sign({
user_id: user_id
}, '1000000000@qq.com', {
expiresIn: 60 //過期時間設置為60
});
return token;
};
4:服務器端驗證token是否正確文件checkToken.js
const jwt = require('jsonwebtoken');
//檢查token是否過期
module.exports = function(req, res, next) {
// 獲取請求頭文件中的token信息
let token = req.body.token || req.query.token || req.headers['authorization'];
console.log(token)
// 解析 token
if (token) {
// 確認token是否正確
let decoded = jwt.decode(token, '1000000000@qq.com');
console.log(decoded,44444)
// 驗證token是否過期
if(token && decoded.exp <= new Date()/1000){
return res.json({ success: false, message: 'token過期' });
}else{
return next();
}
} else {
// 如果沒有token,則返回錯誤
return res.status(403).send({
success: false,
message: '沒有提供token!'
});
}
};
5:服務器端啟動文件
const express = require("express");
var bodyParser=require('body-parser');
const app = express();
const api = require('./router/api')
// 跨域設置
app.all("*", function(req, res, next) {
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
// 設置請求頭類型 添加token res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
next();
});
app.use(bodyParser.urlencoded({extended:true}));
app.use("/api", api);
app.get('/', (req, res) => {
res.send('Hello World');
});
const port = process.env.PORT || 3001;
app.listen(port, () => {
console.log('Express server listening on port ' + port);
});
module.exports = app;
6:vue中用戶登錄操作
login () {
let params = new URLSearchParams();
params.append('username', this.login_username);
params.append('password', this.login_password);
let _token = localStorage.getItem('token');
let that = this;
console.log(_token)
axios.post('http://localhost:3001/api/login', params, {headers:{'Content-Type':'application/x-www-form-urlencoded','Authorization': _token}})
.then(function(res){
console.log(res)
if(res.data.success){
let token = res.data.token;
localStorage.setItem('token', token);
that.$router.push({
path: '/index'
})
}
})
.catch(function(err){
console.log(err)
});
},
