原创:微信小程序java实现AES解密并获取unionId

如果大家使用小程序的同时还在使用公众号的话,可能会用到unionId这种功能,由于公司业务需要,我们需要使用unionId,具体使用方法,请参考微信开放平台的说明,但是在微信小程序的文档中只给出了部分语言实现的源码,竟然没有Java的,小程序的开发人员是有多么懒。难道大家都不用java写后台???


什么鬼,然后开始了各种AES踩坑之路,其实参考了很多的网上的教程,再次不能一一列出来给大家了,(因为我写这篇文章的时候,已经是解决问题一周以后了),也收到管理员的很多帮助,再次写个帖子回馈大家吧,在此只列出unionId的解密方式,如果有什么问题,联系我或者回帖都可以。


另外稍加吐槽一下, 
https 不要用startcom提供的免费证书! 
https 不要用startcom提供的免费证书! 
https 不要用startcom提供的免费证书!


重要的事情说三遍!!!!


AES.java

[java]  view plain  copy
  1. <span style="font-family:Microsoft YaHei;font-size:12px;">import org.apache.commons.codec.binary.Base64;  
  2. import org.bouncycastle.jce.provider.BouncyCastleProvider;  
  3. import javax.crypto.BadPaddingException;  
  4. import javax.crypto.Cipher;  
  5. import javax.crypto.IllegalBlockSizeException;  
  6. import javax.crypto.NoSuchPaddingException;  
  7. import javax.crypto.spec.IvParameterSpec;  
  8. import javax.crypto.spec.SecretKeySpec;  
  9. import java.security.*;  
  10. public class AES {  
  11.     public static boolean initialized = false;  
  12.     /** 
  13.      * AES解密 
  14.      * @param content 密文 
  15.      * @return 
  16.      * @throws InvalidAlgorithmParameterException 
  17.      * @throws NoSuchProviderException 
  18.      */  
  19.     public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {  
  20.         initialize();  
  21.         try {  
  22.             Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");  
  23.             Key sKeySpec = new SecretKeySpec(keyByte, "AES");  
  24.             cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化  
  25.             byte[] result = cipher.doFinal(content);  
  26.             return result;  
  27.         } catch (NoSuchAlgorithmException e) {  
  28.             e.printStackTrace();  
  29.         } catch (NoSuchPaddingException e) {  
  30.             e.printStackTrace();  
  31.         } catch (InvalidKeyException e) {  
  32.             e.printStackTrace();  
  33.         } catch (IllegalBlockSizeException e) {  
  34.             e.printStackTrace();  
  35.         } catch (BadPaddingException e) {  
  36.             e.printStackTrace();  
  37.         } catch (NoSuchProviderException e) {  
  38.             // TODO Auto-generated catch block  
  39.             e.printStackTrace();  
  40.         } catch (Exception e) {  
  41.             // TODO Auto-generated catch block  
  42.             e.printStackTrace();  
  43.         }  
  44.         return null;  
  45.     }  
  46.     public static void initialize(){  
  47.         if (initialized) return;  
  48.         Security.addProvider(new BouncyCastleProvider());  
  49.         initialized = true;  
  50.     }  
  51.     //生成iv  
  52.     public static AlgorithmParameters generateIV(byte[] iv) throws Exception{  
  53.         AlgorithmParameters params = AlgorithmParameters.getInstance("AES");  
  54.         params.init(new IvParameterSpec(iv));  
  55.         return params;  
  56.     }  
  57. }</span>  

WxPKCS7Encoder.java

[javascript]  view plain  copy
  1. <span style="font-family:Microsoft YaHei;font-size:12px;">import java.nio.charset.Charset;  
  2. import java.util.Arrays;  
  3. /** 
  4. * Created by Kevin Dong on 2017/1/5. 
  5. */  
  6. public class WxPKCS7Encoder {  
  7.     private static final Charset CHARSET = Charset.forName("utf-8");  
  8.     private static final int BLOCK_SIZE = 32;  
  9.     /** 
  10.      * 获得对明文进行补位填充的字节. 
  11.      * 
  12.      * @param count 需要进行填充补位操作的明文字节个数 
  13.      * @return 补齐用的字节数组 
  14.      */  
  15.     public static byte[] encode(int count) {  
  16.         // 计算需要填充的位数  
  17.         int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);  
  18.         if (amountToPad == 0) {  
  19.             amountToPad = BLOCK_SIZE;  
  20.         }  
  21.         // 获得补位所用的字符  
  22.         char padChr = chr(amountToPad);  
  23.         String tmp = new String();  
  24.         for (int index = 0; index < amountToPad; index++) {  
  25.             tmp += padChr;  
  26.         }  
  27.         return tmp.getBytes(CHARSET);  
  28.     }  
  29.     /** 
  30.      * 删除解密后明文的补位字符 
  31.      * 
  32.      * @param decrypted 解密后的明文 
  33.      * @return 删除补位字符后的明文 
  34.      */  
  35.     public static byte[] decode(byte[] decrypted) {  
  36.         int pad = decrypted[decrypted.length - 1];  
  37.         if (pad < 1 || pad > 32) {  
  38.             pad = 0;  
  39.         }  
  40.         return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);  
  41.     }  
  42.     /** 
  43.      * 将数字转化成ASCII码对应的字符,用于对明文进行补码 
  44.      * 
  45.      * @param a 需要转化的数字 
  46.      * @return 转化得到的字符 
  47.      */  
  48.     public static char chr(int a) {  
  49.         byte target = (byte) (a & 0xFF);  
  50.         return (char) target;  
  51.     }  
  52. }</span>  

调用方法解密如下:

[java]  view plain  copy
  1. <span style="font-family:Microsoft YaHei;font-size:12px;">WechatOpenIdRes wechatInfo  = getWehatInfoByCode(code);  
  2.         if(wechatInfo != null && wechatInfo.isOk()){  
  3.             boolean isNew = true;  
  4.             try {  
  5.                 AES aes = new AES();  
  6.                 byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(wechatInfo.getSession_key()), Base64.decodeBase64(iv));  
  7.                 if(null != resultByte && resultByte.length > 0){  
  8.                      String userInfo = new String(WxPKCS7Encoder.decode(resultByte) ,"UTF-8");  
  9.                     WxInfo wxInfo = GsonUtil.fromGson(userInfo, WxInfo.class);  
  10.                     if(wxInfo != null) {  
  11.                         logger.debug("xxxxxunionid===="+wxInfo.getUnionId());  
  12.                     }  
  13.                 }  
  14.             } catch (InvalidAlgorithmParameterException e) {  
  15.                 e.printStackTrace();  
  16.             } catch (Exception e) {  
  17.                 e.printStackTrace();  
  18.             }</span>  

编译环境为java1.8 
另外我引入的support 包为 
bcprov-jdk16-139.jar 此包已上传附件, 
顺带附上我试用的小程序js中的代码吧,

[javascript]  view plain  copy
  1. <span style="font-family:Microsoft YaHei;font-size:12px;">var code ="";  
  2. wechat.login()  
  3.       .then(function(res){  
  4.         code = res.code;          
  5.       })  
  6.       .then(function(){  
  7.         return wechat.getUserInfo();  
  8.       })  
  9.       .then(function(res){  
  10. var encryptedData = res.encryptedData  
  11. var iv = res.iv;  
  12. return userservice.getUserToken(code,encryptedData,iv);  
  13.       })</span>  

上面的代码使用了promise,其中最后一句userservice.getUserToken为请求服务器的方法,参数为获取到的code+加密内容+初始化向量

有什么问题可以联系我。

qq:403125094

源码下载地址:http://www.wxapp-union.com/portal.php?mod=view&aid=1189
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
微信小程序获取unionid的步骤如下: 1. 开发者在小程序后台配置小程序的AppID、AppSecret以及启用相关的接口权限。 2. 用户在小程序中进行登录,获取到用户的openid和session_key。 3. 利用session_key进行解密获取到用户的用户敏感数据,其中包括unionid。 4. 使用解密后的unionid,开发者可以将其与用户在小程序中的其他信息进行关联,方便后续业务的处理。 根据上述步骤,下面是一个示例代码片段来实现获取unionid的功能: ```javascript // 根据用户的code获取用户的openid和session_key wx.login({ success: function(res) { if (res.code) { // 发起网络请求,调用后台接口获取openid和session_key wx.request({ url: 'https://api.weixin.qq.com/sns/jscode2session', data: { appid: 'wxXXXXXXXXXXXXXXX', // 小程序的AppID secret: 'XXXXXXXXXXXXXXXXX', // 小程序的AppSecret js_code: res.code, grant_type: 'authorization_code' }, success: function(res) { var openid = res.data.openid; var sessionKey = res.data.session_key; // 解密用户敏感数据,获取unionid var encryptedData = "XXXXXXXXXXXXXXXXX"; // 用户加密的数据 var iv = "XXXXXXXXXXXXXXXXX"; // 加密算法的初始向量 var pc = new WXBizDataCrypt(appId, sessionKey); var data = pc.decryptData(encryptedData , iv); var unionId = data.unionId; // 将unionid与其他用户信息关联存储 // TODO: 进行后续业务处理 } }); } else { console.log('登录失败!' + res.errMsg); } } }); ``` 其中,需要开发者自行实现一个WXBizDataCrypt类,用于解密用户敏感数据,可以参考微信官方提供的相关文档进行实现。 这样,开发者就可以在小程序中获取到用户的unionid,方便后续的用户关联及业务处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值