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君的代码备忘
转载请联系作者获得授权并注明出处。
留言