微信小程序:获取本机号码的正确方式

本来写过一篇获取手机号码出错的博客:

微信小程序获取手机号解密偶尔出错:Padding is invalid and cannot be removed._我想我是海 冬天的大海 心情随风轻摆-CSDN博客

但实际上还是没有给出具体的解决方案,这里补充。

事实上,即使能用,但老是要用户试第2次,用户体验还是不会好,所以还是来点正确的姿势吧。

前提:小程序必须先做好微信认证。没有认证的会有各种各样的错误。

设置→基本设置→微信认证

一、小程序端相关代码:

1. app.js

增加函数: getOpenidAndSave

  //获取openid,而且保存到缓存
  getOpenidAndSave(opt) {
    var that = this;
    wx.login({
      success(res) {
        console.log("getOpenidAndSave, wx.login: success, ", res);
        let jsCode =res.code;
        if (res.code) {
          // 换取微信openId
          that.post({
            method: "POST",
            url: "xxx/getWechatOpenId",//获取openId的接口
            data: {
              Value: res.code
            },
            success: ret => {
              console.log("xxx/getWechatOpenId, success:", ret);
              // 获取到微信openId
              let data = JSON.parse(ret)
              let openId = data.openid;
              let session_key = data.session_key;
              console.log("保存openid之前输出:", openId);
              //保存openid
              wx.setStorageSync('OPENID',openId);
              if(opt && opt.success){
                opt.success(openId, session_key, jsCode);
              }
            },
            err: (res) => {
              console.log("s_Wechat/getWechatOpenId, err:", res);
            }
          })
        }else{
          console.log("getOpenidAndSave, wx.login: success, 但未获取到code");
        }
      },
      fail(res) {
        console.log("getOpenidAndSave, wx.login: fail, ", res);
      }
    })
  },

2. wxml 页面里面的按钮

注意 open-type 必须是:getPhoneNumber

<button class="btn" open-type="getPhoneNumber" bindgetphonenumber="onGetCurrMobile"   >获取本机号码</button>

3. 当前页面.js 

data 里面增加 2 项

  data: {
    ...
    //一键登录2要素
    session_key: '',
    openId: ''
  },

 onShow :

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    let that = this;
    console.log('onShow');
    //立即获取一次 openId 和 session_key, 便于后面的一键登录
    app.getOpenidAndSave({
      success: (openId,session_key,jsCode) => {
        that.setData({
          session_key: session_key,
          openId: openId
        });
      }
    });
  },

获取手机号码按钮上的事件:

  onGetCurrMobile(e){
    let that = this;
    if(e.detail.errMsg=="getPhoneNumber:fail user deny"){
      wx.showToast({
        title: '您选择了拒绝,无法使用本机认证的方式',
        icon: 'none'
      })
      return false;
    }
    var para = {
      EncryptedData: e.detail.encryptedData,
      IV: e.detail.iv,
      SessionKey: that.data.session_key,
      OpenId: that.data.openId
    };
    //已有所有需要的参数,直接请求
    app.post({
      url: 'xxx/getPhoneNumber2', //接口地址
      data: para,
      success: function (phoneNumber) {
        console.log("已获取到正确手机号=", phoneNumber);
        //写上你自己的业务代码
      },
      err: function(res){
        console.log(res);
      }
    });
  },

二. C#后台

1. 获取本机号码的接口:

        /// <summary>
        /// 获取手机号V2,不会有出错
        /// </summary>
        /// <param name="code">code</param>
        /// <returns></returns>
        [HttpPost]
        public MapResponse GetPhoneNumber2([FromBody] ParaWxGetPhoneNumber2 para)
        {
            string phoneNumber = new WechatHelper().DecryptPhoneNumber(para.EncryptedData, para.IV, para.SessionKey);
            if (phoneNumber.StartsWith("Padding"))
            {
                phoneNumber = "意外错误,请重试";
            }
            //如果手机号不正确,返回的是特殊的错误信息
            if (!ValidateUtil.IsMobile(phoneNumber))
            {
                return MapResponse.Fail(ResponseCode.SYSTEM_INVALID, phoneNumber);
            }
            //否则返回正确的手机号
            return MapResponse.Success(phoneNumber);
        }

 2. WechatHelper.cs 相关方法:

        /// <summary>
        /// AES解密:从小程序中 getPhoneNumber 返回值中,解析手机号码
        /// </summary>
        /// <param name="encryptedData">包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法</param>
        /// <param name="IV">加密算法的初始向量</param>
        /// <param name="Session_key"></param>
        /// <returns>手机号码</returns>
        public string DecryptPhoneNumber(string encryptedData, string IV, string Session_key)
        {
            try
            {
                byte[] encryData = Convert.FromBase64String(encryptedData);  // strToToHexByte(text);
                RijndaelManaged rijndaelCipher = new RijndaelManaged();
                rijndaelCipher.Key = Convert.FromBase64String(Session_key); // Encoding.UTF8.GetBytes(AesKey);
                rijndaelCipher.IV = Convert.FromBase64String(IV);// Encoding.UTF8.GetBytes(AesIV);
                rijndaelCipher.Mode = CipherMode.CBC;
                rijndaelCipher.Padding = PaddingMode.PKCS7;
                ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
                byte[] plainText = transform.TransformFinalBlock(encryData, 0, encryData.Length);
                string result = Encoding.Default.GetString(plainText);
                //动态解析result 成对象
                dynamic model = Newtonsoft.Json.Linq.JToken.Parse(result) as dynamic;
                return model.phoneNumber;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

总结一下,重点还是 onShow 那里就立即获取到 session_key 。

虽然可以在后面按钮里请求时再来获取,但那时很容易导致第1次请求出错。

为什么要获取到 openid?

如果只是获取手机号,那是用不着。但如果是 本机号码一键登录,那就有用了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值