后台使用node-rsa生成公鑰和私鑰---->
后台寫個獲取公鑰的接口(將公鑰轉化為指定格式)---->
前端調用接口獲取公鑰---->
前端使用JSEncrypt中間件設置公鑰,並加密密碼---->
前端將加密后的數據通過接口(如登錄接口)傳給后台---->
后台使用密鑰加密前端加密的數據,在用解密后的數據查詢或者保存到數據庫中
1.安裝包
"jsencrypt": "^3.0.0-rc.1",
"node-rsa": "^1.0.5",
備注:使用Node開發時,建議安裝nodemon,可以熱加載后台改的代碼,超級好用,只需要安裝一下包,在啟動的使用nodemon app.js
即可
2.后台生成公鑰和密鑰
const NodeRSA = require('node-rsa'); const fs = require('fs'); //生成公鑰 function generator() { var key = new NodeRSA({ b: 512 }) key.setOptions({ encryptionScheme: 'pkcs1' }) var privatePem = key.exportKey('pkcs1-private-pem') var publicPem = key.exportKey('pkcs8-public-pem') fs.writeFile('./pem/public.pem', publicPem, (err) => { if (err) throw err console.log('公鑰已保存!') }) fs.writeFile('./pem/private.pem', privatePem, (err) => { if (err) throw err console.log('私鑰已保存!') }) } generator();
這樣就可以在pem目錄下生成兩個文件:private.pem和public.pem,看文件名就知道誰是公鑰誰是密鑰了哈。
注意(此處有坑)---前端加密后的數據始終為false
之前自己也是在網上復制的代碼,有一個地方有問題,對比一下哈

1.png
在導出公鑰和密鑰的時候,exportKey的參數相同,都為pkcs1,這就導致了前端獲取到了公鑰加密之后的數據為始終為false。找了好久才知道問題所在,追溯在node-rsa中的源碼可以看到:

4.png
exportKey中的參數是有固定的值的,不然就會導致導出的公鑰或者私鑰有問題。
3.后台設置獲取公鑰接口供前端使用
router.get('/api/getPublicKey', (req, res) => {
try {
let publicKey = fs.readFileSync('./pem/public.pem', 'utf-8');
console.log('publicKey', publicKey)
res.send({ 'status': 0, 'msg': '公鑰獲取成功', 'resultmap': publicKey });
} catch (err) {
res.send(err);
}
})
我使用的是Express中間件哈,使用Koa或者其他中間件的自行修改。
4.前端獲取公鑰並加密數據傳給后台
import { JSEncrypt } from "jsencrypt"; that.$axios .get(webUrl + "getPublicKey") .then(res => { if (res.data.status === 0) { let encryptor = new JSEncrypt(); //實例化 encryptor.setPublicKey(res.data.resultmap); //設置公鑰 console.log(that.password); console.log(encryptor.encrypt(a)); let data = { name: that.name, password: encryptor.encrypt(that.password), //加密 nickName: that.nickName }; that.$axios .post(webUrl + "admin/signUp", data) .then(response => { that.$message({ type: "success", message: response.data.msg }); if (response.data.status == 1) { that.back(); } }) .catch(reject => { console.log(reject); }); } }) .catch(err => { console.log(err); });
5.后台用私鑰解密
// 注冊 router.post('/api/admin/signUp', (req, res) => { //是否重名 db.User.find({ name: req.body.name }, (err, docs) => { if (err) { res.send(err); return } if (docs.length > 0) { res.send({ 'status': 0, 'msg': '用戶名已注冊' }); } else { db.User.find({ nickName: req.body.nickName }, (err, docs) => { if (err) { res.send(err); return } if (docs.length > 0) { res.send({ 'status': 0, 'msg': '昵稱已注冊' }); } else { const privateKey = fs.readFileSync('./pem/private.pem', 'utf8'); //讀取私鑰 let buffer1 = Buffer.from(req.body.password, 'base64'); //轉化格式 let password = crypto.privateDecrypt({ key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING // 注意這里的常量值要設置為RSA_PKCS1_PADDING }, buffer1).toString('utf8'); console.log('解密之后的密碼', password); let newUser = new db.User({ name: req.body.name, password: password, nickName: req.body.nickName, avatar: null, // type: req.body.type type: 2//1為管理員,2為游客,寫死,新建管理員數據庫直接改 }); newUser.save(function (err) { if (err) { res.send(err); } else { res.send({ 'status': 1, 'msg': '注冊成功' }); } }) } }) } }) })
經驗證,后台解密后的密碼和前端加密前的數據一致,說明加密和解密的過程都OK。加密和解密有很多種方法的,以上總結是自己嘗過OK的一種,特此總結一下,希望能幫助到其他人。
作者:快樂女孩筱梅
鏈接:https://www.jianshu.com/p/ccf6d3f6be1a
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。