Add WXBizDataCrypt for WeChat Mini Program.

This commit is contained in:
Sutra Zhou 2018-04-30 15:56:39 +08:00
parent 6382fe6195
commit 75c10cb035
8 changed files with 224 additions and 5 deletions

8
.gitignore vendored
View File

@ -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

View File

@ -18,7 +18,11 @@ weixin4j
* **weixin4j-qy[1.7.8]** * **weixin4j-qy[1.7.8]**
`企业号API封装` `企业号API封装`
* **weixin4j-wxa[1.7.9]**
`小程序 API 封装`
* **weixin4j-server[1.1.8]** * **weixin4j-server[1.1.8]**
`netty服务器&消息分发` `netty服务器&消息分发`

View File

@ -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>

49
weixin4j-wxa/pom.xml Normal file
View 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.7.9</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>

View File

@ -0,0 +1,58 @@
package com.foxinmy.weixin4j.wxa;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.NoSuchProviderException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
final class AESUtils {
private static boolean initialized = false;
private AESUtils() {
}
/**
* AES解密
*
* @param content 密文
* @return 明文
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)
throws InvalidAlgorithmParameterException {
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 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;
}
}

View File

@ -0,0 +1,48 @@
package com.foxinmy.weixin4j.wxa;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import org.apache.commons.codec.binary.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
/**
* @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;
}
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[] resultByte;
try {
resultByte = AESUtils.decrypt(aesCipher, aesKey, aesIV);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
final String decryptedText = new String(resultByte, 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;
}
}

View File

@ -0,0 +1,4 @@
/**
* <a href="https://developers.weixin.qq.com/miniprogram/dev/api/">WeChat Mini Program</a> support library.
*/
package com.foxinmy.weixin4j.wxa;

View File

@ -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"));
}
}