微信小程序解密手机号

371 阅读3分钟

在微信小程序解密 手机号,虽然一般都是由后端进行解密的。。但。。。

步骤

  • 获取 session_key
  • 通过button组件获取手机号信息
  • 使用Crypto 插件进行解密

主要就是通过 wx.login 获取到 code,再调用code2Session 接口获取 session_key, 然后引导用户点击button获取加密数据ivencryptedData,最后通过Crypto 插件进行解密。

第一步, 获取session_key

使用 wx.login 获取 code, 然后调用后端提供的 api 获取session_key,然后对session_key 进行存储

后端提供的api其实就是调用微信的code2Session接口,但小程序不能直接访问,微信在公众平台做了限制: 不能添加https://api.weixin.qq.com 作为服务器域名。

遇到的坑:
  • session_key 在获取到加密数据后获取,导致解密手机号失败! session_key 必须在用户点击 button之前获取,因为当用户点击后微信会 根据当前的session_key加密数据。解密时,需要使用 加密时的session_key 配合。

你可能不知道的 session_key ?!

我们在 获取到用户加密数据后才去获取session_key,则很大概率解密失败。而且调用 wx.login 后会刷新session_key...所以最好将session_key 存储起来,而且session_key 的有效期是不确定的,根据用户使用小程序的频率有关。频率越高,有效期越长。

第二步, 通过引导用户点击 button 组件 获取加密数据

获取手机号 需要 认证的小程序,个人开发者不行, 查看官方解释 获取关于手机号的信息必要要通过用户点击button 才能获取, 先给button 加上open-type='getPhoneNumber' 然后再加上触发后的回调bindgetphonenumber

  //wxml 代码
  ...
  <button open-type="getPhoneNumber" bindgetphonenumber={{getPhoneNumberFn}}></button>
  
 // js代码
  ....
  // 获取到加密信息
  getPhoneNumberFn(phoneDetail){
     const { iv, encryptedData } = phoneDetail.detail;
  }

第三步,使用Crypto 插件进行解密

  • 首先需要添加Crypto 插件
    分为两部分

      1. 在公众平台小程序账号中添加插件,步骤如下
      1. 在小程序项目根目录下的app.json中 将 插件添加到 plugins字段中,步骤如下

      公众平台小程序账号中添加插件

      将插件添加到项目中
      这里的 Crypto 会作为引入的字段名,versionprovider 分别是 插件的版本 和 插件开发者的 appid 可以从这里获取: crypto 详细内容

  • 然后使用Crypto 插件进行解密 解密需要用到session_keyiv,encryptedData ,其中 iv,encryptedData 是通过用户点击 button 获取。

    下面提供我自己写的一个解密方法decode,使用时传入 session_keyiv,encryptedData 这三个参数即可,返回值 info 中包含解密后的内容,如果解密失败,则返回 null


const crypto = requirePlugin('Crypto');// 使用插件

/**
 * 解密手机号
 * @param session_key string
 * @param iv  string
 * @param encryptedData  string
 * @return info 解密后的手机号
 */
export const decode = function(session_key , iv, encryptedData) {
  const mode = ['CBC'];
  const padding = ['Pkcs7'];
  let info = null
  try {
    var mykey = crypto.Base64.parse(session_key)
    var myiv = crypto.Base64.parse(iv)
    var myEncryptedData = crypto.Base64.parse(encryptedData)
    var aesCipher = crypto.Base64.stringify(myEncryptedData)
    mode.map((modeItem) => {
      padding.map((paddingItem) => {
        const v = new crypto.AES().decrypt(aesCipher, mykey, {
          iv: myiv,
          mode: crypto.Mode[modeItem],
          padding: crypto.Padding[paddingItem]
        });
        console.log(crypto.Utf8, v.toString(crypto.Utf8))
        var data = JSON.parse(v.toString(crypto.Utf8))
        if (data && data.watermark && data.watermark.appid ===  APP_ID) {
          info = data;
        }
        console.log('解密成功的数据:',info)
      })
    })
  } catch (e) {
    console.log('decode error:', e);
    //info = decode(session_key, iv,encryptedData)
  }
  return info;
}