jsencrypt加密和解密的那点事


后台使用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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM