uniapp加密解密(RSA,AES),无第三方认证

思路:

未登录:

  1. 生成一对RSA公钥私钥,公钥事先放在前端中,省去获取后端公钥的过程(防止被拦截,无法判断是否是后端传来的公钥)
  2. 用户未登陆时,通过公钥加密账号信息发送至后端,这样即便被窃取也无法得知内容
  3. 后端返回登陆生成的token,refresh token需要进行加密,理想办法是前端生成一对RSA公钥私钥,公钥发给后端加密,但是前端加密一般使用的node-rsa过大,微信小程序基本一引用就超出限制,uniapp压缩代码,分段都没用,所以放弃
  4. 前端将账号密码通过默认规则拼接成新字符串并MD5加密,作为对称加密密钥和账号传给后端,并加密token,refresh token返回。(token刷新问题可查看解决token刷新问题​​​​​​​)

登录后:

  1. 依旧生成一对RSA公钥私钥,公钥事先放在前端中,私钥存后端
  2. 前端通过对称加密AES加密数据,token,refresh token。将密钥通过准备好的RSA公钥加密,添加到请求头部
  3. 后端收到请求通过私钥解密头部,获得密钥解密数据
  4. 后端返回数据通过前端传的密钥AES加密返回。

实现加密解密:

对称加密AES使用crypto-js,非对称加密RSA使用jsencrypt

使用npm安装:

初始化

npm init -y

引入crypto-js

npm install crypto-js

jsencrypt需要用到window变量,小程序不支持,解决办法有很多,这里直接下载jsencrypt.zip-小程序文档类资源-CSDN下载

然后引入使用就可以了

AES.js

import cryptoJs from 'crypto-js'
//对称加密
var initkey = 'thisisker'//秘钥
var keySize = 128;// 设置数据块长度
var iv = cryptoJs.enc.Utf8.parse('ABCDEF1234123412');   //十六位十六进制数作为密钥偏移量

export default{
 //填充秘钥
    getKey(){
        let filledKey = Buffer.alloc(keySize / 8);
        let keys = Buffer.from(initkey);
        if (keys.length < filledKey.length) {
            filledKey.map((b, i) => filledKey[i] = keys[i]);
        }
        return  filledKey;
    },
// 加密函數
    jiami (dat) {
        //获取填充后的key
        let key = cryptoJs.enc.Utf8.parse(this.getKey());
        let enc = ''
        //判断非string类型使用JSON.stringify转换
        let data;
        if (typeof dat==='string'){
            data =dat
        }else {
            data = JSON.stringify(dat)
        }
        //加密
        enc = cryptoJs.AES.encrypt(data, key, {
            mode: cryptoJs.mode.CBC,
            padding: cryptoJs.pad.Pkcs7,
            iv: iv
        })
        // 将加密后的数据转换成 Base64
        let encString = enc.ciphertext.toString(cryptoJs.enc.Base64);
        // 处理 Android 某些低版的BUG
        let encResult=encString.replace(/\+/g,'-').replace(/\//g,'_');
        return encResult;
    },
    // 解密函數
    jiemi(dat){
        //获取填充后的key
        let key = cryptoJs.enc.Utf8.parse(this.getKey());
        //先将Base64还原一下,因为加密的时候做了一些字符的替换
        const restoreBase64 = dat.replace(/\-/g,'+').replace(/_/g,'/');
        //返回的是解密后的对象
        let decrypt = cryptoJs.AES.decrypt(restoreBase64,key,{
            mode:cryptoJs.mode.CBC,
            padding:cryptoJs.pad.Pkcs7,
            iv:iv
        });
        //将解密对象转换成UTF8的字符串
        let decryptedStr = cryptoJs.enc.Utf8.stringify(decrypt);
        //返回解密结果
        return decryptedStr;
    }
}

 RSA.js

import JSEncrypt  from "./jsencrypt"//存放路径

//传入数据,公钥私钥
export default {
    jiami(dat,publicKey){
        let data;
        if (typeof dat==='string'){
            data =dat
        }else {
            data = JSON.stringify(dat)
        }
        let encrypt = new JSEncrypt();
        encrypt.setPublicKey(publicKey);	  // 公钥
        let encryptMsg = encrypt.encrypt(data);
        return encryptMsg;
    },

    jiemi(data,privateKey){
        let decrypt = new JSEncrypt();
        decrypt.setPrivateKey(privateKey);	  // 私钥
        let decryptMsg = decrypt.decrypt(data);
        return decryptMsg;
    }
}

如有可优化地方请提出

你可能感兴趣的:(https,网络协议,http)