網(wǎng)址:http://www.reibang.com/p/58abb716b5dc/
具體概念參考上面鏈接
Token驗(yàn)證的基本流程
1.服務(wù)端收到請(qǐng)求廓奕,去驗(yàn)證用戶名與密碼
2.驗(yàn)證成功后县爬,服務(wù)端會(huì)簽發(fā)一個(gè) Token,再把這個(gè) Token 發(fā)送給客戶端
3.客戶端收到 Token 以后可以把它存儲(chǔ)起來(lái)返十,比如放在 Cookie 里或者 Local Storage 里
4.客戶端每次向服務(wù)端請(qǐng)求資源的時(shí)候需要帶著服務(wù)端簽發(fā)的 Token
5.服務(wù)端收到請(qǐng)求策肝,然后去驗(yàn)證客戶端請(qǐng)求里面帶著的 Token肛捍,如果驗(yàn)證成功,就向客戶端返回請(qǐng)求的數(shù)據(jù)
JWT標(biāo)準(zhǔn)的Token有如下三個(gè)部分
header (頭部)
payload (數(shù)據(jù))
signature (簽名)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInVzZXJfaWQiOjEsImlhdCI6MTU5NDI2MjQ5NSwiZXhwIjoxNTk0MzQ4ODk1fQ.1MJ_MAFgpBjOjpggj69Xz8F_evBcMAenRK_7a8fdVrc
安裝
//生成token與驗(yàn)證
1.jsonwebtoken
npm install jsonwebtoken --save
* 生成token的方法 sign
* 驗(yàn)證token的方法 verify
2.express-jwt
npm install express-jwt --save
* 驗(yàn)證token是否過(guò)期并規(guī)定那些路由不需要驗(yàn)證 express-jwt({})
token Express后端相關(guān)代碼
定義生成token和獲取token的函數(shù)
/token/token.js
const jwt = require('jsonwebtoken');
// 密鑰
const jwtSecret = 'dkfjdjfkdfdfd'; //簽名
//登錄接口 生成token的方法
// setToken攜帶的參數(shù)及參數(shù)的數(shù)量自定義
const setToken = function (user_name) {
return new Promise((resolve, reject) => {
//expiresln 設(shè)置token過(guò)期的時(shí)間
//{ user_name: user_name, user_id: user_id } 傳入需要解析的值( 一般為用戶名之众,用戶id 等)
// const token = jwt.sign({ user_name: user_name }, jwtSecret, { expiresIn: '24h' });
const token = jwt.sign({ user_name: user_name }, jwtSecret, { expiresIn: '10s' });
resolve(token)
})
}
//各個(gè)接口需要驗(yàn)證token的方法
const getToken = function (token) {
return new Promise((resolve, reject) => {
if (!token) {
console.log('token是空的')
reject({
error: 'token 是空的'
})
}
else {
// 驗(yàn)證token
var info = jwt.verify(token.split(' ')[1], jwtSecret);
resolve(info); //解析返回的值(sign 傳入的值)
}
})
}
module.exports = {
setToken,
getToken
}
解析token,驗(yàn)證token
app.js
const express = require("express")
const app = express()
//express跨域
const cors = require("cors")
// 生成token和驗(yàn)證token是否正確的函數(shù)
const vertoken=require('./token/token')
//驗(yàn)證token是否過(guò)期拙毫,并規(guī)定哪些路由不用驗(yàn)證token
const expressJwt=require('express-jwt')
const bookRouter = require("./router/bookRouter")
const userRouter = require("./router/userRouter")
app.use(cors())
//允許訪問(wèn)upload下的靜態(tài)資源
app.use(express.static("upload"))
// 解析post請(qǐng)求的參數(shù)
app.use(express.json())
//=============================================驗(yàn)證token
//解析token獲取用戶信息
app.use(function(req, res, next) {
let token = req.headers['authorization'];
if(token == undefined){
next();
}else{
vertoken.getToken(token).then((data)=> {
console.log('解析后的token',data);
req.data = data;
next();
}).catch((error)=>{
next();
})
}
});
//驗(yàn)證token是否過(guò)期并規(guī)定那些路由不需要驗(yàn)證
app.use(expressJwt({
secret:'dkfjdjfkdfdfd',
// 加密算法
algorithms:['HS256']
}).unless({
path:['/login'] //不需要驗(yàn)證的接口名稱(chēng)
}))
//設(shè)置托管靜態(tài)目錄; 項(xiàng)目根目錄+ public.可直接訪問(wèn)public文件下的文件eg:http://localhost:3000/images/url.jpg
//token失效返回信息
app.use(function(err,req,res,next){
if(err.status==401){
res.status(401).send('token失效11111111')
}
})
app.use(bookRouter)
app.use(userRouter)
app.listen(3000, () => {
console.log("服務(wù)器已開(kāi)啟在3000端口");
})
登錄接口
/router/usersRouter.js
const express = require("express")
const router = express.Router()
const conn = require("../db/db")
const vertoken = require("../token/token")
// 查詢商品
router.post("/login", (req, res) => {
let { user_name, pw } = req.body;
let sql = "select * from admin where user_name = ? and pw = ?"
conn.query(sql, [user_name, pw], function (err, result) {
if (err) {
console.log('查詢數(shù)據(jù)庫(kù)失敗');
} else {
let data;
if (result.length) {
//==============================================調(diào)用生成token的方法
vertoken.setToken(user_name).then(token => {
data = {
code: 0,
message: '登錄成功',
token: token
//前端獲取token后存儲(chǔ)在localStroage中,
//**調(diào)用接口時(shí) 設(shè)置axios(ajax)請(qǐng)求頭Authorization的格式為`Bearer ` +token
}
res.send(data)
})
} else {
data = {
code: 1,
msg: '登錄失敗 '
}
res.send(data)
}
}
})
})
module.exports = router
token Vue前端相關(guān)代碼
登錄后獲取token
login(this.ruleForm)
.then((res) => {
console.log('login返回的數(shù)據(jù)');
if (res.data.code == 0) {
this.$message({
message: "登錄成功",
center: true,
});
//存儲(chǔ)token
localStorage.setItem("token",res.data.token)
this.$router.push("/Layout")
}
});
前端請(qǐng)求攜帶token
api/config.js
import axios from 'axios'
// 給所有axios請(qǐng)求設(shè)置基礎(chǔ)的域名
// axios.defaults.baseURL = 'http://localhost:3000'
//用axios.create可以創(chuàng)建axios的實(shí)例,允許不同實(shí)例有不同配置
const axios1 = axios.create({
baseURL: 'http://localhost:3000',
// 請(qǐng)求超時(shí)的時(shí)間
timeout: 5000
});
// const axios2 = axios.create({
// baseURL: 'http://www.test.com',
// timeout: 5000
// });
//添加請(qǐng)求攔截器棺禾,會(huì)在發(fā)起請(qǐng)求之前執(zhí)行相應(yīng)的需求
axios1.interceptors.request.use(function (config) {
// console.log('我是請(qǐng)求攔截器');
config.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem("token");
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// //添加響應(yīng)攔截器缀蹄,會(huì)在返回?cái)?shù)據(jù)后先執(zhí)行相應(yīng)的需求
axios1.interceptors.response.use(function (response) {
console.log('我是響應(yīng)攔截器');
// Do something with response data
return response;
}, function (error) {
// Do something with response error
console.log('error',error.status);
return Promise.reject(error);
});
export default axios1