http請求特點是無狀態的,也即是請求接口者未知,爲了防止隨意訪問,加一個身份驗證。在登錄成功以後,發佈一個加密字符串(用戶信息相關),給前端,以後每次給後端請求接口,都要將加密字符串傳遞給後端來驗證。
處理該問題總體有兩種方式:
1、session+cookie 跨域不可用cookie,導致ip不一致時候容易出現問題,用起來麻煩
- 需要用到的node插件有兩個:cookie-parse和express-session
- 使用該插件,登錄成功後會自動生成cookie給前端
使用步驟:
在服務中引入插件並做配置:
const session = require('express-session');
const cookParse = require('cookie-parse');
...
// 在需要攔截的地方進行中間件配置
app.use('/food',(req, res, next)=>{
if(req.body.session.login){
next()
}else{
res.send({success: false, message: '沒有登錄,請先登錄'});
}
}, foodRouter);
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true,
cookie: { masAge: 60 * 1000 * 60 } //設置過期時間
}));
在登錄接口中,登錄成功以後,由於安裝了express-session插件並配置了,在req.body.session能獲取到seeeion值,同理也可以賦值,登錄成功後,做如下處理:
router.post('/login', (req,res)=>{
const {us, ps}=req.body;
if(us&&ps){
User.find({name: us,pass: ps}).then(data=>{
if(data.length>0){
// 給session設置值
req.session.login=true;
req.session.name=us;
res.send({success: true, message: '登錄成功', user:data});
}else{
res.send({success: false, message: '賬號或者密碼錯誤'});
}
}).catch(error=>{
res.send({success:false, message: '程序錯誤請聯繫管理員'});
})
}else{
res.send({success: false, message: '缺少參數'})
}
})
之後再訪問food模塊內容東西,由於配置了攔截器,如果獲取不到session中的login,就會返回失敗信息。
- 如何清除session呢?
在退出接口做如下配置就可:
router.get('/logOut', (req,res)=>{
req.session.destroy();
res.send({message: '退出成功', success: true})
});
這樣就會清除掉cookie信息,並清除登錄session。
2、使用jwt是json web token 簡寫
前端登錄時候,後端返回一個token,以後每次調接口都要傳遞此token,沒有token就會驗證不通過,禁止訪問。
jwt又分爲兩類,一類是對稱性加密,一種是非對稱加密。
打開jwt官網,就會發現有三部分組成,一個是頭信息,確定使用那種加密方式,圖中使用的是hs256(哈希256),第二個是參數,第三個是私鑰通過你隨便輸入的私鑰,輸的越亂越好。通過加密算法將前兩個合成一個東西,生成藍色的內容,就是token。注意不要在payload中放密碼信息,通過官網能解析出來token。
1、下面使用node的jsonwebtoken插件來實現對稱性加密,默認採用hs256:
// 簡單實現
const jwt=require('jsonwebtoken');
const payload={
us: 'ling',
login: true,
};
const screat = 'jsladfjklsdjlkfjlk;asdjlfk;jaskldjfklas';
// 生成token
const token=jwt.sign(payload, screat, {expiresIn: 300}); // hs256 數據 載荷 screat私鑰 過期時間,單位是秒,設爲5分鐘過期
// 驗證token合法性
jwt.verify(token, screat, (err,data)=>{
console.log(err, data)
})
console.log(token);
2、封裝函數
const jwt=require('jsonwebtoken');
const screat = 'jsladfjklsdjlkfjlk;asdjlfk;jaskldjfklas';
// 生成token
function createToken(payload){
return jwt.sign(payload, screat, { expiresIn: 180 });// 設置過期時間爲3分鐘
}
// 驗證token合法性
function checkedToken(token) {
return new Promise((resolve, reject)=>{
jwt.verify(token, screat, (err, data)=>{
if(err){reject('token驗證失敗')}
resolve(data);
})
})
}
module.exports={
createToken,
checkedToken,
}
將上述封裝函數放在utils文件下,文件命名爲jwt。在登錄成功接口,做如下處理:
const JWT=require('../utils/jwt');
router.post('/login', (req,res)=>{
const {us, ps}=req.body;
if(us&&ps){
User.find({name: us,pass: ps}).then(data=>{
if(data.length>0){
const token=JWT.createToken({login: true, name: us});
res.send({success: true, message: '登錄成功', user:data, token});
}else{
res.send({success: false, message: '賬號或者密碼錯誤'});
}
}).catch(error=>{
res.send({success:false, message: '程序錯誤請聯繫管理員'});
})
}else{
res.send({success: false, message: '缺少參數'})
}
})
前端將token信息保存到本地,以後調用接口將該token傳進去。
後端在需要登錄才能訪問的功能下,服務中加如攔截器:
const JWT=require('../utils/jwt');
app.use('/food',(req, res, next)=>{
const {token}=req.body;
JWT.checkedToken(token).then((data)=>{
next()
}).catch((err)=>{
res.send({success: false, message: 'token無效'});
})
}, foodRouter);