小程序中使用jsencrypt

1,670 阅读3分钟

小程序中无法直接使用jsencrypt,直接上错误信息如下

点开错误信息,可见小程序环境中中是没有navigator对象的,所以代码中才会报错

全局搜了一遍源码中navigator相关代码有两处:

源码中有用到navigator.appName和navigator.userAgent两个字段,我们分析两处代码,对于appName主要用与判断浏览器选择不同的大数处理方式,这里我们可以考虑直接删除其他代码选择am3,或者构造一个navigator.appName = 'Netscape';对于userAgent主要用于IE11之前的浏览器做兼容处理,对此我们也可以直接给userAgent赋值来绕过。

// 可以直接从浏览器中取值
var navigator = {
    appName: 'Netscape',
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
};

解决完navigator会发现还有类似问题,window对象同样是不存在的,依葫芦画瓢

源码中中使用到window对象的地方主要是在有crypto属性时做rng_pool的初始化,以及mousemove的事件监听,这里没有添加事件并没不会影响到加密,所以直接给一个空的window对象也是可以的。

// 用到的window属性基本是用于判断是否使用window对象提供的方法,只要相关代码不报错就好了。
var window = {
    crypto: null
}

到这一步就不会再报错了,可以使用jsencrypt中的方法来做加密解密了

    const Key = 'TEST KEY';
    const encrypt = new JSEncrypt();
    // 这里使用指定的公钥
    encrypt.setPublicKey(`-----BEGIN PUBLIC KEY-----
   your public key
    -----END PUBLIC KEY-----`);
    let encryptedKey = encrypt.encrypt(Key);

mpvue中引入jsEncrypt

拷贝一份jsEncrypt源码,然后按照以上的方式进行修改,直接引入使用

const {JSEncrypt} = require('./jsencrypt');
const encrypt = new JSEncrypt();

不出意外会有以下报错,反正我是遇到了。。。

怎么搞呢,导出的JSEncrypt是undefined,见鬼了。看源码中,其实已经是做了模块化的包装,在mpvue中还会有一次打包,会将代码再做一次封装,那么我直接把源码中的包装代码移除然后export JSEncrypt就好了

/* eslint-disable */
// (function (global, factory) {
// 	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
// 	typeof define === 'function' && define.amd ? define(['exports'], factory) :
// 	(factory((global.JSEncrypt = {})));
// }(this, (function (exports) { 
'use strict';
.....


export default JSEncrypt// 新加的导出
// window.JSEncrypt = JSEncrypt;

// exports.JSEncrypt = JSEncrypt;
// exports.default = JSEncrypt;


// Object.defineProperty(exports, '__esModule', { value: true });

// })));

到此已经可以在mpvue中愉快地使用JSEncrypt了。

encrypt 方法默认输出的是base64

    /**
     * Proxy method for RSAKey object's encrypt, encrypt the string using the public
     * components of the rsa key object. Note that if the object was not set will be created
     * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor
     * @param {string} str the string to encrypt
     * @return {string} the encrypted string encoded in base64
     * @public
     */
    JSEncrypt.prototype.encrypt = function (str) {
        // Return the encrypted string.
        try {
            return hex2b64(this.getKey().encrypt(str));
        }
        catch (ex) {
            return false;
        }
    };

如果项目使用的是hex那就需要再进行一次转换了,如果项目也和我一样使用到了CryptoJS,那可以这样操作。

//encryptedString 是JSEncrypt加密后输出的base64串
CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encryptedString))

如果没有用到CryptoJS,也可以直接把源码中的hex2b64移除,或者把源码中的b64tohex方法导出使用。

参考