Merge pull request #136 from sutra/wxa
Add WXBizDataCrypt for WeChat Mini Program.
This commit is contained in:
commit
ec04f2302f
8
.gitignore
vendored
8
.gitignore
vendored
@ -12,9 +12,9 @@ hs_err_pid*
|
|||||||
*~
|
*~
|
||||||
|
|
||||||
# eclipse ignore
|
# eclipse ignore
|
||||||
*.settings/*
|
.settings/
|
||||||
/.project
|
.project
|
||||||
/.classpath
|
.classpath
|
||||||
/.tomcatplugin
|
/.tomcatplugin
|
||||||
|
|
||||||
# idea ignore
|
# idea ignore
|
||||||
@ -22,7 +22,7 @@ hs_err_pid*
|
|||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
# maven ignore
|
# maven ignore
|
||||||
target/*
|
target/
|
||||||
|
|
||||||
# other ignore
|
# other ignore
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@ -19,6 +19,10 @@ weixin4j
|
|||||||
|
|
||||||
`企业号API封装`
|
`企业号API封装`
|
||||||
|
|
||||||
|
* **weixin4j-wxa[1.8.0]**
|
||||||
|
|
||||||
|
`小程序 API 封装`
|
||||||
|
|
||||||
* **weixin4j-server[1.1.8]**
|
* **weixin4j-server[1.1.8]**
|
||||||
|
|
||||||
`netty服务器&消息分发`
|
`netty服务器&消息分发`
|
||||||
|
|||||||
3
pom.xml
3
pom.xml
@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>weixin4j</name>
|
<name>weixin4j</name>
|
||||||
<url>https://github.com/foxinmy/weixin4j</url>
|
<url>https://github.com/foxinmy/weixin4j</url>
|
||||||
@ -43,6 +43,7 @@
|
|||||||
<module>weixin4j-base</module>
|
<module>weixin4j-base</module>
|
||||||
<module>weixin4j-mp</module>
|
<module>weixin4j-mp</module>
|
||||||
<module>weixin4j-qy</module>
|
<module>weixin4j-qy</module>
|
||||||
|
<module>weixin4j-wxa</module>
|
||||||
<module>weixin4j-server</module>
|
<module>weixin4j-server</module>
|
||||||
<module>weixin4j-example</module>
|
<module>weixin4j-example</module>
|
||||||
<module>weixin4j-serverX</module>
|
<module>weixin4j-serverX</module>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>weixin4j-base</artifactId>
|
<artifactId>weixin4j-base</artifactId>
|
||||||
<name>weixin4j-base</name>
|
<name>weixin4j-base</name>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
<artifactId>weixin4j-example</artifactId>
|
<artifactId>weixin4j-example</artifactId>
|
||||||
@ -48,13 +48,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j-mp</artifactId>
|
<artifactId>weixin4j-mp</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 微信企业号 -->
|
<!-- 微信企业号 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j-qy</artifactId>
|
<artifactId>weixin4j-qy</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 微信被动消息(回调模式) -->
|
<!-- 微信被动消息(回调模式) -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>weixin4j-mp</artifactId>
|
<artifactId>weixin4j-mp</artifactId>
|
||||||
<name>weixin4j-mp</name>
|
<name>weixin4j-mp</name>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>weixin4j-qy</artifactId>
|
<artifactId>weixin4j-qy</artifactId>
|
||||||
<name>weixin4j-qy</name>
|
<name>weixin4j-qy</name>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>weixin4j-server</artifactId>
|
<artifactId>weixin4j-server</artifactId>
|
||||||
<version>1.1.9</version>
|
<version>1.1.9</version>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.foxinmy</groupId>
|
<groupId>com.foxinmy</groupId>
|
||||||
<artifactId>weixin4j</artifactId>
|
<artifactId>weixin4j</artifactId>
|
||||||
<version>1.7.9</version>
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>weixin4j-serverX</artifactId>
|
<artifactId>weixin4j-serverX</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.0.1</version>
|
||||||
|
|||||||
49
weixin4j-wxa/pom.xml
Normal file
49
weixin4j-wxa/pom.xml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.foxinmy</groupId>
|
||||||
|
<artifactId>weixin4j</artifactId>
|
||||||
|
<version>1.8.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>weixin4j-wxa</artifactId>
|
||||||
|
<name>weixin4j-wxa</name>
|
||||||
|
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-wxa</url>
|
||||||
|
<description>微信小程序 API 支持</description>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.foxinmy</groupId>
|
||||||
|
<artifactId>weixin4j-base</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.55</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>1.1.8</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.foxinmy.weixin4j.wxa;
|
||||||
|
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
final class AESUtils {
|
||||||
|
|
||||||
|
private static boolean initialized = false;
|
||||||
|
|
||||||
|
private AESUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES解密
|
||||||
|
*
|
||||||
|
* @param content 密文
|
||||||
|
* @param keyByte key
|
||||||
|
* @param ivByte 初始向量
|
||||||
|
* @return 明文
|
||||||
|
*/
|
||||||
|
static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) {
|
||||||
|
initialize();
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
|
||||||
|
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
|
||||||
|
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte)); // 初始化
|
||||||
|
byte[] result = cipher.doFinal(content);
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized void initialize() {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AlgorithmParameters generateIV(byte[] iv) throws Exception {
|
||||||
|
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
|
||||||
|
params.init(new IvParameterSpec(iv));
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.foxinmy.weixin4j.wxa;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对微信小程序用户加密数据的解密.
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/api/signature.html#wxchecksessionobject">加密数据解密算法</a>
|
||||||
|
*/
|
||||||
|
public class WXBizDataCrypt {
|
||||||
|
|
||||||
|
private final String appid;
|
||||||
|
|
||||||
|
private final String sessionKey;
|
||||||
|
|
||||||
|
public WXBizDataCrypt(String appid, String sessionKey) {
|
||||||
|
this.appid = appid;
|
||||||
|
this.sessionKey = sessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密微信小程序用户加密数据.
|
||||||
|
*
|
||||||
|
* @param encryptedData 加密的用户数据.
|
||||||
|
* @param iv 与用户数据一同返回的初始向量.
|
||||||
|
* @return 解密后的原文.
|
||||||
|
*/
|
||||||
|
public JSONObject decryptData(final String encryptedData, final String iv) {
|
||||||
|
final byte[] aesKey = Base64.decodeBase64(sessionKey);
|
||||||
|
final byte[] aesCipher = Base64.decodeBase64(encryptedData);
|
||||||
|
final byte[] aesIV = Base64.decodeBase64(iv);
|
||||||
|
|
||||||
|
final byte[] decryptedBytes = AESUtils.decrypt(aesCipher, aesKey, aesIV);
|
||||||
|
final String decryptedText = new String(decryptedBytes, Charset.forName("UTF-8"));
|
||||||
|
final JSONObject decrypted = JSON.parseObject(decryptedText);
|
||||||
|
|
||||||
|
final String appId = decrypted.getJSONObject("watermark").getString("appid");
|
||||||
|
if (!appId.equals(this.appid)) {
|
||||||
|
throw new IllegalArgumentException("Invalid Buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* <a href="https://developers.weixin.qq.com/miniprogram/dev/api/">WeChat Mini
|
||||||
|
* Program</a> support library.
|
||||||
|
*
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
package com.foxinmy.weixin4j.wxa;
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package com.foxinmy.weixin4j.wxa;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
public class WXBizDataCryptTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecryptData() {
|
||||||
|
String appId = "wx4f4bc4dec97d474b";
|
||||||
|
String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";
|
||||||
|
|
||||||
|
WXBizDataCrypt biz = new WXBizDataCrypt(appId, sessionKey);
|
||||||
|
|
||||||
|
String encryptedData
|
||||||
|
= "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM"
|
||||||
|
+ "QmRzooG2xrDcvSnxIMXFufNstNGTyaGS"
|
||||||
|
+ "9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+"
|
||||||
|
+ "3hVbJSRgv+4lGOETKUQz6OYStslQ142d"
|
||||||
|
+ "NCuabNPGBzlooOmB231qMM85d2/fV6Ch"
|
||||||
|
+ "evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6"
|
||||||
|
+ "/1Xx1COxFvrc2d7UL/lmHInNlxuacJXw"
|
||||||
|
+ "u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn"
|
||||||
|
+ "/Hz7saL8xz+W//FRAUid1OksQaQx4CMs"
|
||||||
|
+ "8LOddcQhULW4ucetDf96JcR3g0gfRK4P"
|
||||||
|
+ "C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB"
|
||||||
|
+ "6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns"
|
||||||
|
+ "/8wR2SiRS7MNACwTyrGvt9ts8p12PKFd"
|
||||||
|
+ "lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV"
|
||||||
|
+ "oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG"
|
||||||
|
+ "20f0a04COwfneQAGGwd5oa+T8yO5hzuy"
|
||||||
|
+ "Db/XcxxmK01EpqOyuxINew==";
|
||||||
|
String iv = "r7BXXKkLb8qrSNn05n0qiA==";
|
||||||
|
|
||||||
|
JSONObject data = biz.decryptData(encryptedData, iv);
|
||||||
|
|
||||||
|
assertEquals("CN", data.getString("country"));
|
||||||
|
assertEquals("ocMvos6NjeKLIBqg5Mr9QjxrP1FA", data.getString("unionId"));
|
||||||
|
assertEquals(1, data.getIntValue("gender"));
|
||||||
|
assertEquals("Guangdong", data.getString("province"));
|
||||||
|
assertEquals("Guangzhou", data.getString("city"));
|
||||||
|
assertEquals("http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0", data.getString("avatarUrl"));
|
||||||
|
assertEquals("oGZUI0egBJY1zhBYw2KhdUfwVJJE", data.getString("openId"));
|
||||||
|
assertEquals("Band", data.getString("nickName"));
|
||||||
|
assertEquals("zh_CN", data.getString("language"));
|
||||||
|
|
||||||
|
JSONObject watermark = data.getJSONObject("watermark");
|
||||||
|
assertEquals("wx4f4bc4dec97d474b", watermark.getString("appid"));
|
||||||
|
assertEquals(1477314187L, watermark.getLongValue("timestamp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user