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

2024-08-28 08:32

本文主要是介绍原创:微信小程序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

这篇关于原创:微信小程序java实现AES解密并获取unionId的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1114256

相关文章

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏