springboot微信小程序用户敏感信息解密获取unionId,因为在不同平台中,openId可能会不同,只有unionId能唯一确认一个用户。需要解密微信的敏感信息才能得到用户的唯一标识 unionId。这里使用 springboot 来完成这个过程。

首先,前端使用wx.login方法获取js_code传回给后端,后端通过微信登录接口登录获取用户的session_key,以备后续使用。

// 微信登录请求参数
public static final String WECHAT_APP_ID = "ur app id";
public static final String WECHAT_SECRET = "ur secret";
public static final String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code";

public Map<String, Object> wechatLogin(String code) {
  Map<String, Object> resultMap = new HashMap<>();
  // 微信登录
  RestTemplate restTemplate = new RestTemplate();
  // 组装登录地址
  StringBuilder loginUrl = new StringBuilder(WECHAT_LOGIN_URL);
  loginUrl.append("&appid=").append(WECHAT_APP_ID);
  loginUrl.append("&secret=").append(WECHAT_SECRET);
  loginUrl.append("&js_code=").append(code);
  // 微信登录
  String loginResultStr = restTemplate.getForObject(loginUrl.toString(), String.class);
  /*
   * 手动将sb微信发过来的text头的json转化为对象
   * 这里为啥说微信sb呢,因为,你发给我个json,然而你的header里面写的text,导致spring不能直接转对象!
   */
  ObjectMapper mapper = new ObjectMapper();
  UserWechatLoginResultBean loginResult;
  try {
    loginResult = mapper.readValue(loginResultStr, UserWechatLoginResultBean.class);
    if(null == loginResult.getErrcode() || 0 == loginResult.getErrcode()) {
      String openId = loginResult.getOpenid();
      String sessionKey = loginResult.getSession_key();

      resultMap.put("openId", openId);
      /*
       * TODO sessionkey不应该传给前端,
       * 应该和用户的相关信息对应的存在后端,我这里不详细写
       */
      // resultMap.put("sessionKey", sessionKey);
    } catch (JsonParseException e) {
      e.printStackTrace();
      resultMap.put("errCode", ResultCodes.SYSTEM_ERROR_JSON_PARSE);
      resultMap.put("errMsg", e.getMessage());
    }
  }
  return resultMap;
}

返回结果用到的实体UserWechatLoginResultBean.java

/**
 * 用户微信登录返回信息
 * 
 * @author ckun
 *
 */
public class UserWechatLoginResultBean {

  private String openid;
  
  private String session_key;
  
  private String unionid;
  
  private Integer errcode;
  
  private String errmsg;

  
  // getters & setters
  .
  .
  .
}

解密信息需要一个jar的支持,我们在pom中添加

<!-- 微信解密 -->
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.61</version>
</dependency>

添加解密方法的几个方法

// 微信关键信息解密
private static final String KEY_ALGORITHM = "AES";
private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
private static Key key;
private static Cipher cipher;

/**
 * 微信关键信息解密
 * 
 * @param encryptDataB64
 * @param sessionKeyB64
 * @param ivB64
 * @return
 */
public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
  return new String(
    decryptOfDiyIV(
      Base64.decode(encryptDataB64),
      Base64.decode(sessionKeyB64),
      Base64.decode(ivB64)
    )
  );
}
  
private static void init(byte[] keyBytes) {
  // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
  int base = 16;
  if (keyBytes.length % base != 0) {
    int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
    byte[] temp = new byte[groups * base];
    Arrays.fill(temp, (byte) 0);
    System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
    keyBytes = temp;
  }
  // 初始化
  Security.addProvider(new BouncyCastleProvider());
  // 转化成JAVA的密钥格式
  key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
  try {
    // 初始化cipher
    cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
  } catch (Exception e) {
    e.printStackTrace();
  }
}
  
/**
 * 解密方法
 *
 * @param encryptedData 要解密的字符串
 * @param keyBytes      解密密钥
 * @param ivs           自定义对称解密算法初始向量 iv
 * @return 解密后的字节数组
 */
private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
  byte[] encryptedText = null;
  init(keyBytes);
  try {
    cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
    encryptedText = cipher.doFinal(encryptedData);
  } catch (Exception e) {
    e.printStackTrace();
  }
  return encryptedText;
}

在小程序端wx.getUserInfo获得的参数中,前端传回encryptedData和vi两个参数,与后端的session_key一起解密,即可获得用户敏感信息;

// 解密关键数据
String decryptStr = decryptData(encryptData, sessionKey, iv);
// json数据解析
UserWechatDecryptDateBean encryptDataBean = mapper.readValue(decryptStr, UserWechatDecryptDateBean.class);

解密用的数据实体UserWechatDecryptDateBean.java

/**
 * 微信用户关键信息解密数据
 * 
 * @author ckun
 *
 */
public class UserWechatDecryptDateBean {

  private String avatarUrl;
  
  private String city;
  
  private String country;
  
  private Integer gender;
  
  private String language;
  
  private String nickName;
  
  private String openId;
  
  private String province;
  
  private String unionId;
  
  private UserWechatDecryptDateWaterMarkBean watermark;

  
  // getters & setters
  .
  . 
  .
}

UserWechatDecryptDateWaterMarkBean.java

/**
 * 微信用户加密信息水印
 * 
 * @author ckun
 *
 */
public class UserWechatDecryptDateWaterMarkBean {
  
  private Long timestamp;
  
  private String appid;

 
  // getters & setters
  .
  . 
  .
}

====================
作者:ckun
链接:https://ckun.xyz/2019/05/springboot微信小程序用户敏感信息解密获取unionId/
来源:C君的代码备忘
转载请联系作者获得授权并注明出处。

最后修改日期: 2020年5月11日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。