Java后端解密微信小程序手机号数据

小程序端登录后,得到登录时获取的 code(仅可使用一次)

App({
 onLaunch: function () {
       // 登录
       wx.login({
         success: res => {
           // 发送 res.code 到后台换取 openId, sessionKey, unionId
           console.log(res.code)
         }
           })
   }
})

2.后端访问微信登录凭证校验API
小程序官方文档地址-登录凭证.
通过官方提供的接口,获取到会话密钥session_key和openid
https://api.weixin.qq.com/sns/jscode2session?appid=‘小程序id’&secret='小程序AppSecret '&js_code=‘步骤1中得到的code’&grant_type=authorization_code

3.小程序请求客户授权获取手机号
小程序官方文档地址-获取手机号
(1)页面上增加一个按钮,用户点击后获取到敏感数据

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>

(2)将e.detail传到后端

Page({
  getPhoneNumber (e) {
    console.log(e.detail.errMsg)
    console.log(e.detail.iv)
    console.log(e.detail.encryptedData)
  }
})

4.结合sessionKey、encryptedData、iv三个参数,进行解密操作

二、Java后端解密数据

基于jdk1.8,低于1.8版本需要创建一个base64解密工具类

1、实体类

(1)微信手机号信息解密后的对象

public class WeixinPhoneDecryptInfo {

    private String phoneNumber;
    private String purePhoneNumber;
    private int countryCode;
    private String weixinWaterMark;
    private WaterMark watermark;
}
public class WaterMark {
    private Long timestamp;// 时间戳做转换的时候,记得先乘以1000,再通过simpledateformat完成date类型转换
    private String appid;

    ...
}

2、解密工具类

这一部分的代码,参考链接博客链接书写,感谢博主!
实际使用中,由于特殊字符存在,可能导致base64解密失败,推荐引入org.apache.xmlbeans.impl.util.Base64,而不是java.util.Base64,感谢Prometheus_K反馈!

import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.alibaba.fastjson.JSON;

public class AESForWeixinGetPhoneNumber {

    //加密方式
    private static String keyAlgorithm = "AES";
    //避免重复new生成多个BouncyCastleProvider对象,因为GC回收不了,会造成内存溢出
    //只在第一次调用decrypt()方法时才new 对象
    private static boolean initialized = false;
    //用于Base64解密
    private Base64.Decoder decoder = Base64.getDecoder();

    //待解密的数据
    private String originalContent;
    //会话密钥sessionKey
    private String encryptKey;
    //加密算法的初始向量
    private String iv;

    public AESForWeixinGetPhoneNumber(String originalContent,String encryptKey,String iv) {
        this.originalContent = originalContent;
        this.encryptKey = encryptKey;
        this.iv = iv;
    }

    /**
     * AES解密
     * 填充模式AES/CBC/PKCS7Padding
     * 解密模式128
     *
     * @return 解密后的信息对象
     */
    public WeixinPhoneDecryptInfo decrypt() {
        initialize();
        try {
            //数据填充方式
            //Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS7Padding”,”BC”);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm);
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv)));
            byte[]data = cipher.doFinal(decoder.decode(this.originalContent));
            String datastr = new String(data, StandardCharsets.UTF_8);
            return JSON.toJavaObject(JSON.parseObject(datastr),WeixinPhoneDecryptInfo.class);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(222);
            return null;
        }
    }

    /**BouncyCastle作为安全提供,防止我们加密解密时候因为jdk内置的不支持改模式运行报错。**/
    private static void initialize() {
        if (initialized) {
            return;
        }
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    // 生成iv
    private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException {
        AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm);
        params.init(new IvParameterSpec(iv));
        return params;
    }
}

需要引入的jar包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.61</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.46</version>
</dependency>

测试

public Object a(String encryptedData,String iv,String sessionKey){
        System.out.println("加密的敏感数据:" + encryptedData);
        System.out.println("初始向量:" + iv);
        System.out.println("会话密钥:" + sessionKey);
        String appId = "XXXXXXXXX";
        AESForWeixinGetPhoneNumber aes = new AESForWeixinGetPhoneNumber(encryptedData,sessionKey,iv);
        WeixinPhoneDecryptInfo info = aes.decrypt();
        if (null==info){
            System.out.println("error");
        }else {
            System.out.println(info.toString());
            if (!info.getWatermark().getAppid().equals(appId)){
                System.out.println("wrong appId");
            }
        }
        return info;
    }

WeixinPhoneDecryptInfo [phoneNumber=152XXXXXXXX, purePhoneNumber=152XXXXXXXX, countryCode=86, watermark={"appid":"XXXXXXXXXXXXX","timestamp":1600413039}, weixinWaterMark=null]

原文链接: https://blog.csdn.net/weixin_42792301/article/details/101540668

原文地址:https://www.cnblogs.com/yrjns/p/13691483.html