現在比較流行的驗證方式,是帶着token的登錄驗證
原理
1. 登陸時,客戶端發送用戶名密碼
2. 服務端驗證用戶名密碼是否正確,校驗通過就會生成一個有時效的token串,發送給客戶端
3. 客戶端儲存token,一般都會存儲在localStorage或者cookie里面(vue可以存儲與vuex)
4. 客戶端每次請求時都帶有token,可以將其放在請求頭里,每次請求都攜帶token
5. 服務端驗證token,所有需要校驗身份的接口都會被校驗token,若token解析后的數據包含用戶身份信息,則身份驗證通過,返回數據
完整例子
下面來看一個比較完整的例子,有問題可以和我交流哦,我也挺菜的:
第一步,客戶端發送用戶名和密碼; (一般是post過去)
第二步,驗證用戶名密碼是否正確,校驗通過就會生成一個有時效的token串,發送給客戶端
if (data.toString() === req.body.pass){
// 登陸成功,添加token驗證
let sid = req.body.pass + req.body.seccode; //密碼 和 驗證碼組成其sid
let jwt = new JwtUtil(sid); //將用戶sid傳入,生成token
let token = jwt.generateToken();
res.send({status:200,msg:'登陸成功',token:token});
}else{
res.send({status:404,msg:'口令錯誤'})
}
第三步,客戶端儲存token,一般都會存儲在localStorage或者cookie里面(這里我存儲在vuex里面,進行統一管理)
第四步,客戶端每次請求時都帶有token,可以將其放在請求頭里,每次請求都攜帶token
//使用vuex對全局token進行狀態管理
this.$store.dispatch("set_token",res.data.token);
//設置:全局帶token
this.$http.defaults.headers.common['token'] = this.$store.state.token;
store 里index.js:
import Vue from 'vue'
import Vuex from 'vuex'
//使用vuex
Vue.use(Vuex);
//一個store , Vuex.store的 實例
const store = new Vuex.Store({
state: {
token : ''
},
getters:{ // Getter相當於vue中的computed計算屬性
getToken: (state) => {return state.token;}
},
mutations: {
set_token(state,ltoken) { //第一個參數是拿到state對象
localStorage.setItem('token',ltoken);
state.token = ltoken;
},
del_token(state) {
localStorage.removeItem('token');
state.token = '';
}
},
actions: { //注冊actions,類似vue里面的methods
//通過這個修改state里面的值
// 可以直接用mutations修改,但是官方建議使用actions去調用mutations去修改
set_token(context,token) {
context.commit("set_token",token);
},
del_token(context){
context.commit("del_token");
}
}
})
export default
最后一步,服務端驗證token,所有需要校驗身份的接口都會被校驗token,若token解析后的數據包含用戶身份信息,則身份驗證通過,返回數據
(這里,除了一些特定接口,不攔截之外,把攔截的 都需要進行驗證)
(我這里是: /api/fr/articles 前台獲取文章列表的接口不需要攔截; /api/imgCode 生成二維碼的接口不需要攔截 /api/lone 登錄發token的接口不需要攔截)
其他都需要攔截。
app.use(function (req, res, next){
//一共三個接口不需要攔截:
// /imgCode /lone /api/fr/articles
if (req.url != '/api/fr/articles' && req.url != '/api/imgCode' && req.url != '/api/lone') {
let token = req.headers.token;
let jwt = new JwtUtil(token);
let result = jwt.verifyToken();
console.log('result是:',result);
// 如果考驗通過就next,否則就返回登陸信息不正確
if (result == 'err') {
console.log(result);
res.send({status: 403, msg: '登錄已過期,請重新登錄',res: result});
// res.render('login.html');
} else {
next();
}
} else {
next();
}
});
其中:jwt.js怎么寫呢?參考於這篇文章: nodejs 基於token的身份驗證
// 引入模塊依賴
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
// 創建 token 類
class Jwt {
constructor(data) {
this.data = data;
}
//生成token
generateToken() {
let data = this.data;
let created = Math.floor(Date.now() / 1000);
let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_private_key.pem'));//私鑰 可以自己生成
let token = jwt.sign({
data,
exp: created + 60 * 30,
}, cert, {algorithm: 'RS256'});
return token;
}
// 校驗token
verifyToken() {
let token = this.data;
let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_public_key.pem'));//公鑰 可以自己生成
let res;
try {
let result = jwt.verify(token, cert, {algorithms: ['RS256']}) || {};
let {exp = 0} = result, current = Math.floor(Date.now() / 1000);
if (current <= exp) {
res = result.data || {};
}
} catch (e) {
res = 'err';
}
return res;
}
}
module.exports = Jwt;
公私密鑰對,一般可以選擇openssl進行生成.