微信小程序用户手机号验证的两种方法,方法二个人开发可以使用

4,220 阅读1分钟

方法一:通过云函数getPhoneNumber方法

注意:只针对非个人开发者,且完成了认证的小程序开放

1.1 小程序页面通过button元素获取用户授权

<button @getphonenumber="getphonenumber" open-type="getPhoneNumber"></button>
async getphonenumber(e) {
    const errMsg = e.detail.errMsg
    if (errMsg === "getPhoneNumber:ok") {
        // 调用云函数
        const cloudRes = await wx.cloud.callFunction({
            name: 'getPhone' // 自己创建的云函数名称
            data: {
                code: e.detail.code
            }
         })
    }
}

1.2 调用云函数获取手机号

image.png index.js

const cloud = require('wx-server-sdk');

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
});

exports.main = async (event, context) => {
  const { code } = event;
  if (!code) {
    throw new Error('缺少参数code');
  }

  const result = await cloud.openapi.phonenumber.getPhoneNumber({
    code: code,
  });
  return result;
};

配置接口权限 config.json

{
  "permissions": {
    "openapi": [
      "phonenumber.getPhoneNumber"
    ]
  }
}

方法二:后台自行解析

2.1 获取用户授权,调用wx.login登录

<button @getphonenumber="getphonenumber" open-type="getPhoneNumber"></button>
async getphonenumber(e) {
    const errMsg = e.detail.errMsg
    if (errMsg === "getPhoneNumber:ok") {
        uni.login({
            provider: 'weixin',
            success: async (res) => {
                const cloudFunRes = await wx.cloud.callFunction({
                    name: "getPhone", // 自己创建的云函数名称
                    js_code: res.code,
                    encryptedData: e.detail.encryptedData,
                    iv: e.detail.iv
                })
            })
        })
    }
}

调用云函数解析获取手机号

const cloud = require('wx-server-sdk');
const axios = require("axios")
const CryptoJS = require('crypto-js') ;

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
});

const appid = "小程序appid"
const secret = "小程序密钥"

async function getSession_key(js_code) {
    const res = await axios.get(`https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${js_code}&grant_type=authorization_code`)
    return res.data.session_key
}


class WXBizDataCrypt {
  constructor(appId, sessionKey) {
    this.appId = appId;
    this.sessionKey = sessionKey;
  }

  decryptData(encryptedData, iv) {
    // 确保 encryptedData 和 iv 都是 Base64 编码的字符串
    const sessionKey = CryptoJS.enc.Base64.parse(this.sessionKey);
    const encryptedBuffer = CryptoJS.enc.Base64.parse(encryptedData);
    const ivBuffer = CryptoJS.enc.Base64.parse(iv);
    try {
      // 使用 AES 解密
      const decrypted = CryptoJS.AES.decrypt(
        { ciphertext: encryptedBuffer },
        sessionKey,
        {
          iv: ivBuffer,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7,
        }
      );

      // 将解密后的数据转换为 UTF-8 字符串
      const decoded = decrypted.toString(CryptoJS.enc.Utf8);

      // 解析 JSON 数据
      const result = JSON.parse(decoded);

      // 检查解密结果中的 App ID
      if (result.watermark.appid !== this.appId) {
        throw new Error('Illegal Buffer: App ID mismatch');
      }

      return result;
    } catch (err) {
      console.error('解密失败', err);
      throw new Error('Illegal Buffer: ' + err.message);
    }
  }
}


exports.main = async (event, context) => {
  const { js_code, encryptedData, iv } = event;
  const session_key = await getSession_key(js_code)
    
  if(session_key) {
        let pc = new WXBizDataCrypt(appid, session_key);
        try {
            let data = pc.decryptData(encryptedData, iv);
            return {
                code: 1,
                data
            }
        } catch (err) {
             return {
                code: -1,
                msg: '获取失败'
            }
        }
  } else {
      return {
          code: -1,
          msg: '获取失败'
      }
  }
};