最近在弄微信小程序,需要獲取到用戶的unionid等數據,網上有很多帖子,但是自己還是耗費了很長時間,下面分享下總流程及方法(借鑑了網上很多骨灰級大神的文章):
小程序代碼如下:
// 登錄
wx.login({
success: function (r) {
var code = r.code;//登錄憑證
if (code) {
//2、調用獲取用戶信息接口
wx.getUserInfo({
success: function (res) {
console.log({ encryptedData: res.encryptedData, iv: res.iv, code: code })
//3.解密用戶信息 獲取unionId
//...
//3.請求自己的服務器,解密用戶信息 獲取unionId等加密信息
wx.request({
url: '',//自己的服務接口地址
method: 'post',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
data: { encryptedData: res.encryptedData, iv: res.iv, code: code },
success: function (data) {
//4.解密成功後 獲取自己服務器返回的結果
if (data.data.status == 1) {
var userInfo_ = data.data.userInfo;
console.log(userInfo_)
} else {
console.log('解密失敗')
}
},
fail: function () {
console.log('系統錯誤')
}
})
},
fail: function () {
console.log('獲取用戶信息失敗')
}
})
} else {
console.log('獲取用戶登錄態失敗!' + r.errMsg)
}
},
fail: function () {
callback(false)
}
})
下面是java對稱解密的方法
1、首先是工具類
package com.dai7.util;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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 java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
public class AesUtil {
static {
//BouncyCastle是一個開源的加解密解決方案,主頁在http://www.bouncycastle.org/
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES解密
*
* @param data //密文,被加密的數據
* @param key //祕鑰
* @param iv //偏移量
* @param encodingFormat //解密後的結果需要進行的編碼
* @return
* @throws Exception
*/
public static String decrypt(String data, String key, String iv, String encodingFormat) throws Exception {
//被加密的數據
byte[] dataByte = Base64.decodeBase64(data);
//加密祕鑰
byte[] keyByte = Base64.decodeBase64(key);
//偏移量
byte[] ivByte = Base64.decodeBase64(iv);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, encodingFormat);
return result;
}
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
2、後臺接口
@ResponseBody
@RequestMapping(value = "/decodeUserInfo", method = RequestMethod.POST)
public Map decodeUserInfo(String encryptedData, String iv, String code) {
Map map = new HashMap();
//登錄憑證不能爲空
if (code == null || code.length() == 0) {
map.put("status", 0);
map.put("msg", "code 不能爲空");
return map;
}
//小程序唯一標識 (在微信小程序管理後臺獲取)
String wxspAppid = "";
//小程序的 app secret (在微信小程序管理後臺獲取)
String wxspSecret = "";
//授權(必填)
String grant_type = "authorization_code";
//////////////// 1、向微信服務器 使用登錄憑證 code 獲取 session_key 和 openid ////////////////
//請求參數
String params = "appid=" + wxspAppid + "&secret=" + wxspSecret + "&js_code=" + code + "&grant_type=" + grant_type;
//發送請求
String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
//解析相應內容(轉換成json對象)
JSONObject json = JSONObject.parseObject(sr);
//獲取會話密鑰(session_key)
String session_key = json.get("session_key").toString();
//用戶的唯一標識(openid)
String openid = (String) json.get("openid");
//////////////// 2、對encryptedData加密數據進行AES解密 ////////////////
try {
String result = AesUtil.decrypt(encryptedData, session_key, iv, "UTF-8");
if (null != result && result.length() > 0) {
map.put("status", 1);
map.put("msg", "解密成功");
JSONObject userInfoJSON = JSONObject.parseObject(result);
Map userInfo = new HashMap();
userInfo.put("openId", userInfoJSON.get("openId"));
userInfo.put("nickName", userInfoJSON.get("nickName"));
userInfo.put("gender", userInfoJSON.get("gender"));
userInfo.put("city", userInfoJSON.get("city"));
userInfo.put("province", userInfoJSON.get("province"));
userInfo.put("country", userInfoJSON.get("country"));
userInfo.put("avatarUrl", userInfoJSON.get("avatarUrl"));
userInfo.put("unionId", userInfoJSON.get("unionId"));
map.put("userInfo", userInfo);
return map;
}
} catch (Exception e) {
e.printStackTrace();
}
map.put("status", 0);
map.put("msg", "解密失敗");
return map;
}
重點來了:【在工具類中使用了第三方的加解密類庫】
一.引入三方加密庫類方法:
方法一:
(1)去BouncyCastle官網下載provider的包,然後放入$JAVA_HOME\jre\lib\ext目錄下;
(2)修改配置文件$JAVA_HOME\jre\lib\security\java.security,加入一行配置:security.provider.按順序填數字 =org.bouncycastle.jce.provider.BouncyCastleProvider
(3)代碼如下:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes("UTF-8"), "AES"));
cipher.doFinal("QWEASDZS".getBytes("UTF-8"));
方法二:
(1)在代碼中通過maven引入BouncyCastle的包【涉及到jdk版本,我使用的是jdk10,對應版本爲1.56】
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>
2)無需像方式一一樣修改配置文件,直接在代碼中手動添加provider:【工具類中的代碼就是】
二.引入對應的base64包
【參考鏈接:https://jingyan.baidu.com/article/597a06433601db312b52431c.html】