前几天要做一个信息小程序获取用户的手机号码的功能,但是发现,拿到的数据都是加密的,官方并没有提供Java后台的源代码。。。找到了很久,看到这篇文章,学习了,然后在这基础上做了一些修改,emmm是一些修改。
后台用的spring boot框架,所以有些包如果没有的,请自行导入
前台小程序index.js
Page({
onLoad: function () {
var that = this
that.login();
},
/*解密的类型1、用户信息,2、手机号码*/
decode: function (deType) {
var that = this
wx.request({
url: 'http://localhost:8765/decode',
data: {
'encryptedData': that.data.encryptedData,
'iv': that.data.iv,
'session_key': wx.getStorageSync('session_key')
},
method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
// header: {}, // 设置请求的 header
success: function (res) {
// success
that.setData({ decode: res.data.Decode});
if (deType == 2) {
console.log(res)
}
}
})
},
getPhoneNumber: function (e) {
var that = this
wx.checkSession({
// success: function () {
// //session_key 未过期,并且在本生命周期一直有效
// },
fail: function () {
// session_key 已经失效,需要重新执行登录流程
that.login() //重新登录
}
})
that.setData({ iv: e.detail.iv })
that.setData({ encryptedData: e.detail.encryptedData })
that.decode(2)
},
login: function () {
var that = this
wx.login({
success: function (res) {
// success
var code = res.code
if (code) {
that.setData({ code: code })
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session?appid='+你的小程序的appid+'f&secret=' + 你的小程序的secret + '&js_code=' + code + '&grant_type=authorization_code',
/*appid和secret都是生成的固定的*/
success: function (res) {
that.setData({ openid: res.data.openid })
that.setData({ session_key: res.data.session_key })
wx.setStorageSync('session_key', res.data.session_key)
wx.getUserInfo({
success: function (res) {
// success
that.setData({ userInfo: res.userInfo })
that.setData({ iv: res.iv })
that.setData({ encryptedData: res.encryptedData })
that.decode(1)
}
})
}
})
}
}
})
}
})
如果要获取手机号码需要在页面上加个按钮
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号码</button>
maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<!-- JSONObject对象依赖的jar包 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- Json依赖架包下载 -->
</dependencies>
DecodeController.java
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.util.HashMap;
import java.util.Map;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.demo.utils.AESUtil;
import net.sf.json.JSONObject;
@RestController
@CrossOrigin(origins="*",allowCredentials="true",maxAge=360)
public class DecodeController {
/**
*
* @param encryptedData 需要解密的密文,可以是用户信息或者手机号码,或者其它
* @param iv 加密算法的初始向量
* @param session_key 会话密钥
* @return
*/
@RequestMapping(value="decode")
public Map<String, Object> decode(String encryptedData,String iv,String session_key){
Map<String, Object> map = new HashMap<String, Object>();
try {
byte[] resultByte = AESUtil.instance.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(session_key), Base64.decodeBase64(iv));
if(null != resultByte && resultByte.length > 0){
String userInfo = new String(resultByte, "UTF-8");
JSONObject json = JSONObject.fromObject(userInfo);
map.put("Decode", json);
}
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return map;
}
}
AESUtil.java
这里要注意,一般情况下谁都会报错,所以要加一些东西 详情请查看借鉴
Java本身限制密钥的长度最多128位,而AES256需要的密钥长度是256位,因此需要到Java官网上下载一个Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。
官方网站提供了JCE无限制权限策略文件的下载:
JDK6的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
JDK7的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8的下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt。
如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security下覆盖原来文件,记得先备份。
如果安装了JDK,将两个jar文件也放到%JDK_HOME%\jre\lib\security下。
只要做了以上两步,就能正常加解密了。
如果还不行,可以参考这篇文章,里面提供了完整详细的例子和测试用例:
https://www.cnblogs.com/jhuangsjtu/p/8261683.html。
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 java.security.*;
public class AESUtil {
public static final AESUtil instance = new AESUtil();
public static boolean initialized = false;
/**
* AES解密
* @param content 密文
* @return 解密后的字符串
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public 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 (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// 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;
}
}
喝水不忘挖井人,原文借鉴 如有意见,请联系删除