微信小程序获取unionId必须:
1.*注册微信开放平台,绑定需要获取unionid的应用。
2.*
只是通过https://api.weixin.qq.com/sns/jscode2session
是永远拿不到unionId的只能拿session_key和openid,虽然官方说能拿到。
获取的流程:
*客户端(小程序)
wx.login -> code
wx.userInfo -> iv(偏移量) , encryptedData(加密数据) 传给后台。
---------------------------------------------------------------------
Java服务端:
1.必须的依赖,用于解密过程。(或使用mvn加载)
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.59'
// https://mvnrepository.com/artifact/commons-codec/commons-codec
compile group: 'commons-codec', name: 'commons-codec', version: '1.11'
// https://mvnrepository.com/artifact/net.sf.json-lib/json-lib
compile group: 'net.sf.json-lib', name: 'json-lib', version: '2.4'
AES工具类
package yourpkg;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.apache.ofbiz.base.util.Debug;
public class AES {
public static boolean initialized = false;
public final static String module = AES.class.getName();
/**
* AES解密
*
* @param content
* 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Debug.logInfo("content:"+content,module);
Debug.logInfo("keyByte:"+keyByte,module);
Debug.logInfo("ivByte:"+ivByte,module);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Debug.logInfo("cipher:"+cipher,module);
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
Debug.logInfo("sKeySpec:"+sKeySpec,module);
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
Debug.logInfo("result:"+result,module);
return result;
} catch (NoSuchAlgorithmException e) {
Debug.logInfo("NoSuchAlgorithmException",module);
e.printStackTrace();
} catch (NoSuchPaddingException e) {
Debug.logInfo("NoSuchPaddingException",module);
e.printStackTrace();
} catch (InvalidKeyException e) {
Debug.logInfo("InvalidKeyException",module);
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
Debug.logInfo("IllegalBlockSizeException",module);
e.printStackTrace();
} catch (BadPaddingException e) {
Debug.logInfo("BadPaddingException",module);
e.printStackTrace();
} catch (NoSuchProviderException e) {
Debug.logInfo("NoSuchProviderException",module);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
Debug.logInfo("Exception",module);
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void initialize() {
if (initialized)
return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
// 生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
WX工具类
import org.apache.commons.codec.binary.Base64;
import net.sf.json.JSONObject;
import org.apache.ofbiz.base.util.Debug;
import org.apache.commons.codec.binary.Base64;
public class WXUtil {
/**
* 解密数据
* @return
* @throws Exception
*/
public static String decrypt(String appId, String encryptedData, String sessionKey, String iv){
String result = null;
try {
AES aes = new AES();
byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey),
Base64.decodeBase64(iv));
if(null != resultByte && resultByte.length > 0){
result = new String(WxPKCS7Encoder.decode(resultByte));
JSONObject jsonObject = JSONObject.fromObject(result);
return result;
}
} catch (Exception e) {
result = "";
e.printStackTrace();
}
return null;
}
}
解密工具类
import java.nio.charset.Charset;
import java.util.Arrays;
public class WxPKCS7Encoder {
private static final Charset CHARSET = Charset.forName("utf-8");
private static final int BLOCK_SIZE = 32;
/**
* 获得对明文进行补位填充的字节.
*
* @param count
* 需要进行填充补位操作的明文字节个数
* @return 补齐用的字节数组
*/
public static byte[] encode(int count) {
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符
char padChr = chr(amountToPad);
String tmp = new String();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
}
return tmp.getBytes(CHARSET);
}
/**
* 删除解密后明文的补位字符
*
* @param decrypted
* 解密后的明文
* @return 删除补位字符后的明文
*/
public static byte[] decode(byte[] decrypted) {
int pad = decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
/**
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
*
* @param a
* 需要转化的数字
* @return 转化得到的字符
*/
public static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}
}
先通过code 拿 session_key ,这是解密的关键
WECHAT_MINI_PROGRAM_SNS_PATH:
https://api.weixin.qq.com/sns/jscode2session
StringBuffer requestParamSB = new StringBuffer();
requestParamSB.append("appid="+appId);//AK
requestParamSB.append("&secret="+sc);//SC
requestParamSB.append("&js_code="+code);//用户微信授权代码
requestParamSB.append("&grant_type=authorization_code");//授予类型
String responseStr = HttpRequestHelper.sendGet(SysConstant.WECHAT_MINI_PROGRAM_SNS_PATH, requestParamSB.toString());
HttpRequestHelper类
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import net.sf.json.JSONObject;
public class HttpRequestHelper {
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(),"utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
}
然后将这些值传入方法即可,appId可以不要,只是起到校验作用。
WXUtil.decrypt(appId,encryptedData,sessionKey,iv);
微信反馈结果格式:
{"openId":"ofql75ZdllClk7lnuc4","nickName":"Xxx","gender":1,"language":"zh_CN","city":"new york","province":"ina","country":"gogx","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_a2/Q0j4TwGTfTJgWxRlibYMHfVdjCDqibj8lfTch1hwzl2CvcmficSvS2sZh1icXrQhwJlCFS4LwknHd3F7FWfnxg/1d2","unionId":"opDl4wlzx_QrxyN4vxm1A","watermark":{"timestamp":154222947163,"appid":"wxc3asdr3v5b32b3531f3a"}}
注意:
当你无法解密或者解密出的结果为空时,(或者出现pad block corrupted 报错)
请友善提示前端同学,可能是他的问题。
参考:
微信小程序解密encryptedData 报错:pad block corrupted 解决方法https://blog.csdn.net/l523115401/article/details/80251859
分享到:
相关推荐
微信小程序在进行用户登录时,为了确保数据的安全性,会涉及到加密解密的过程。这个过程通常包括以下几个关键步骤,我们在此详细阐述。 1. **openid的获取** - `openid`是微信为每个小程序用户分配的唯一标识,...
在微信小程序中,获取用户信息时,为了保护用户隐私和数据安全,微信采用了加密的方式传输敏感数据,如`openId`、`unionId`等。本文将深入解析微信小程序用户信息中的`encryptedData`,以及如何正确解密并使用这些...
可能会用到unionId这种功能,由于公司业务需要,我们需要使用unionId,具体使用方法,请参考微信开放平台的说明,但是在微信小程序的文档中只给出了部分语言实现的源码,竟然没有java的,小程序的开发人员是有多么懒...
Java 实现微信小程序登录态维护的关键在于理解和应用微信官方API,以及在服务端妥善处理接收到的用户信息。首先,微信小程序提供了`wx.login`方法,用于获取用户的临时登录凭证——`code`。这个`code`是安全的,可以...
之前做过一个版本是根据encryptData和Session_key解密得到完整的用户信息(包含union_id)的方法去获取用户信息,由于小程序升级,如今需要废弃encryptData的方式去获取用户信息,改成使用encryptedData的方式获取...
微信小程序Java开发封装包 1、代码说明 src中包名后缀为server的均为服务器端servlet代码,对外提供请求业务,可以直接复制使用 xiaochengxu.user MsgDecipher.java 消息解密类 2、lib包说明 log4j.jar 代码流程中的...
微信小程序在java后台获取unionid等敏感信息,对称加解密jar包
不会直接返回openid以及unionid,这些私密的信息一般会保存在加密字段encryptedData中,如果想要获取需要对encryptedData数据进行解密,这里提供一个后台解密工具类,可供大家方便微信小程序encryptedData数据的解密...