微信小程序获取手机号(Java)

微信小程序官方文档地址 :https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html

获取微信用户绑定的手机号,需先调用wx.login接口。

因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用 button 组件的点击来触发。

注意:目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。

1.WXBizDataCrypt实现类

package com.shucha.deveiface.biz.test;

/**
 * @author tqf
 * @Description 小程序AES解密工具 获取手机号
 * @Version 1.0
 * @since 2021-03-29 11:14
 */
import com.alibaba.fastjson.JSONObject;
import lombok.Data;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;
import java.util.Base64;

@Data
public class WXBizDataCrypt {

    private String appId;
    private String sessionKey;

    public static void main(String[] args) {

        String appId = "wxab1ead30c255c845";
        String sessionKey = "ZMD72RbH5jmjjdU/r9K6/Q==";
        String encryptedData = "Kt3Jo0HchNf/Jog3WOdVi99AqQOiWmRXgd6MbmAVQHkHAZDtPOEtvxaL/1JSe25REfyYT3WFHa6muHo6I8JXjefZYBRCHA2uB2/Em6GiKjQLXjTKLmq/fwJVZ9FJje0wk9DFnPEiS561We1SsdanxPHhT/Tphga354F5si4s9Eh7xVJo4zZwWGVf9OvFRuQrpbxUnziPNaRB5sP5uacLhg==";
        String iv = "UsRFhbsbaDp4BCeaRqmDkg==";

        WXBizDataCrypt pc = new WXBizDataCrypt(appId,sessionKey);
        JSONObject decrypt = pc.decrypt(encryptedData, iv);

        System.out.println(decrypt.toString());

    }

    public WXBizDataCrypt(String appId, String sessionKey) {
        this.appId = appId;
        this.sessionKey = sessionKey;
    }


    /**
     * 解密成json
     *
     * @param encryptedData
     * @param iv
     * @return
     */
    public JSONObject decrypt(String encryptedData, String iv) {
        byte[] encryptedDataDecode = Base64.getDecoder().decode(encryptedData);
        byte[] sessionKeyDecode = Base64.getDecoder().decode(this.sessionKey);
        byte[] ivDecode = Base64.getDecoder().decode(iv);
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        byte[] decodeData = decode(encryptedDataDecode, sessionKeyDecode, ivDecode);
        String stringData = new String(decodeData);
        JSONObject jsonObject = JSONObject.parseObject(stringData);
        return jsonObject;
    }


    /**
     * 解密算法 AES-128-CBC
     * 填充模式 PKCS#7
     *
     * @param encryptedDataDecode 目标密文
     * @return
     * @throws Exception
     */
    private byte[] decode(byte[] encryptedDataDecode, byte[] sessionKeyDecode, byte[] iv) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(sessionKeyDecode, "AES");
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(iv));// 初始化
            byte[] result = cipher.doFinal(encryptedDataDecode);
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 处理iv
     *
     * @param iv
     * @return
     * @throws Exception
     */
    private AlgorithmParameters generateIV(byte[] iv) throws Exception {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }
}

2.实际的解密之后的数据 

{"phoneNumber":"18556355920","watermark":{"appid":"wxab1ead30c255c845","timestamp":1616988812},"purePhoneNumber":"18556355920","countryCode":"86"}

参数 类型 说明
phoneNumber String 用户绑定的手机号(国外手机号会有区号)
purePhoneNumber String 没有区号的手机号
countryCode String 区号

 3.tips遇到的问题

    3.1 javax.crypto.BadPaddingException: pad block corrupted

     这个可能是请求获取数据和解密的顺序导致,顺序依照4执行。

4.正确的做法应该是:

  1. 先才调用的wx.login获取code。
  2. 然后再通过code取到用户的session_key 。
  3. 再通过getPhoneNumber获取了手机号的加密数据。
  4. 最后再用session_key,手机号的加密数据和向量解密获取手机号。

改完之后果然就没有问题。


这是因为调用了wx.login后通过code获得的session_key是新的session_key.

所以,在调用wx.login之前获的加密数据不是用新得session_key加密的数据。

在调用wx.login之后获得的加密数据,才是新得的session_key加密的数据。

 

Guess you like

Origin blog.csdn.net/tanqingfu1/article/details/115299703