什麼是Token
Token 是在服務端產生的,當客戶端傳來的用戶名/密碼驗證通過時,就會在服務器端生成一個Token返回給客戶端,這個Token中包含了用戶信息、過期時間等信息。客戶端接收到返回的token後將其保存,在有效時間內客戶端向服務器端發送請求時只需要帶上這個token即可,無需再帶上用戶名和密碼。
express中進行Token認證
1.安裝 jsonwebtoken
npm install jsonwebtoken --save
2. 在 public文件夾下新建 token.js 文件,用戶token的生成與解析
//用於生成和解析token
var jwt = require('jsonwebtoken');
var signkey = 'mes_qdhd_mobile_xhykjyxgs';
exports.setToken = function(username,userid){
return new Promise((resolve,reject)=>{
const token = jwt.sign({
name:username,
_id:userid
},signkey,{ expiresIn:'1h' });
resolve(token);
})
}
exports.verToken = function(token){
return new Promise((resolve,reject)=>{
var info = jwt.verify(token.split(' ')[1],signkey);
resolve(info);
})
}
3. 在 app.js 中進行token的相關配置,這裏有一點很關鍵,要配置有哪些路由是不需要認證的,比如說登錄接口,在未登錄前客戶端是沒有token的,token必須要通過登錄獲得,因此這個接口必須不能進行token認證。
var vertoken = require('./public/token')
// 解析token獲取用戶信息
app.use(function(req, res, next) {
var token = req.headers['authorization'];
if(token == undefined){
return next();
}else{
vertoken.verToken(token).then((data)=> {
req.data = data;
return next();
}).catch((error)=>{
return next();
})
}
});
//驗證token是否過期並規定哪些路由不用驗證
app.use(expressJwt({
secret: 'mes_qdhd_mobile_xhykjyxgs'
}).unless({
path: ['/login']//除了這個地址,其他的URL都需要驗證
}));
//當token失效返回提示信息
app.use(function(err, req, res, next) {
if (err.status == 401) {
return res.status(401).send('token失效');
}
});
4. 編寫登錄接口
router.post('/login', function(req, res, next) {
var username = req.body.username;
var password = req.body.password;
//生成token
settoken.setToken(username,userid).then((data)=>{
res.json({ token: data });
})
});
5. 獲取數據接口
當未在請求頭中加入token時,是無法獲取到數據的
我們在請求頭中加入token認證信息,這裏要注意一點,一定要使用 Bearer token的格式,即在token前面要加上Bearer。 如下所示:
再次發送請求,可以看到返回了我們想要的信息。但是這個token不是永久有效的,它具有有效期時間,過了有效期當然這個token也就作廢了,需要重新登錄獲取新的token。
有的人按照上面的做法都是一樣的,但是爲什麼還是無法得到數據呢。
這裏有一點肯很容易被忽略,如果在express中設置了請求頭信息中沒有含有Authorization的話,後端是無法接收到token的。
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "content-type");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
這裏需要把 Authorization加入到請求頭中。
res.header("Access-Control-Allow-Headers", "content-type,Authorization");
與VUE對接
在VUE用使用axios請求,可以在axios的請求攔截器中配置token
//請求攔截器
instance.interceptors.request.use(
config => {
const token = store.state.token;
token && (config.headers.Authorization = 'Bearer ' + token);
return config;
},
error => Promise.error(error)
)
還可以對不同的狀態碼進行相應的處理,這裏只舉例幾個
const toLogin = () => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}
const errorHandle = (status) => {
// 狀態碼判斷
switch (status) {
// 401: 未登錄狀態,跳轉登錄頁
case 401:
toLogin() //403 token過期,跳轉登錄頁
break;
case 403:
// tip('登錄過期,請重新登錄');
localStorage.removeItem('token');
store.commit('loginSuccess', null);
setTimeout(() => {
toLogin();
}, 1000);
break;
// 404請求不存在
case 404:
console.log('請求資源不存在');
break;
// default:
}}
往期推薦