微信web开发只需要code值,但是小程序需要一个code值,一个encryptData,一个iv
首先先看图
箭头部分为微信给我们的,就是前端需要传过来的。
步骤为:
- 小程序客户端调用wx.login,回调里面包含js_code。
- 然后将js_code发送到服务器A(开发者服务器),服务器A向微信服务器发起请求附带js_code、appId、secretkey和grant_type参数,以换取用户的openid和session_key(会话密钥)。
- 服务器A拿到session_key后,生成一个随机数我们叫3rd_session,以3rdSessionId为key,以session_key + openid为value缓存到redis或memcached中;因为微信团队不建议直接将session_key在网络上传输,由开发者自行生成唯一键与session_key关联。其作用是:
- 将3rdSessionId返回给客户端,维护小程序登录态。
- 通过3rdSessionId找到用户session_key和openid。
- 客户端拿到3rdSessionId后缓存到storage,
- 通过wx.getUserIinfo可以获取到用户敏感数据encryptedData 。
- 客户端将encryptedData、3rdSessionId和偏移量一起发送到服务器A
- 服务器A根据3rdSessionId从缓存中获取session_key
- 在服务器A使用AES解密encryptedData,从而实现用户敏感数据解密
重点在6、7、8三个环节。
AES解密三个参数:
- 密文 encryptedData
- 密钥 aesKey
- 偏移向量 iv
概念性的东西就这些,下面看代码
首先前端需要传给我们的东西就是三个一个code值,一个encryptData,一个iv,
先写方法
package com.everest.academy.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection; import java.security.AlgorithmParameters; import java.security.Security; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @ClassName XcxUtils * @Description 微信小程序方法 * @Author 田野 * @Data 22:14 * @Version 1.0 **/ @Slf4j public class XcxUtils { /** * 获取微信小程序 session_key 和 openid * * @author zhy * @param code * 调用微信登陆返回的Code * @return */ public static JSONObject getSessionKeyOropenid(String code, String appid, String secret) { String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; // 请求地址 Map<String, String> requestUrlParam = new HashMap<String, String>(); requestUrlParam.put("appid", appid); // 开发者设置中的appId requestUrlParam.put("secret", secret); // 开发者设置中的appSecret requestUrlParam.put("js_code", code); // 小程序调用wx.login返回的code requestUrlParam.put("grant_type", "authorization_code"); // 默认参数 // 发送post请求读取调用微信 https://api.weixin.qq.com/sns/jscode2session // 接口获取openid用户唯一标识 JSONObject jsonObject = JSON.parseObject(sendPost(requestUrl, requestUrlParam)); System.out.println(jsonObject); return jsonObject; } /** * 解密用户敏感数据获取用户信息 * * @author zhy * @param sessionKey * 数据进行加密签名的密钥 * @param encryptedData * 包括敏感数据在内的完整用户信息的加密数据 * @param iv * 加密算法的初始向量 * @return */ public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) { encryptedData=encryptedData.replace(" ", "+"); sessionKey=sessionKey.replace(" ", "+"); iv=iv.replace(" ", "+"); // 被加密的数据 byte[] dataByte = Base64.decode(encryptedData); // 加密秘钥 byte[] keyByte = Base64.decode(sessionKey); // 偏移量 byte[] ivByte = Base64.decode(iv); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16; if (keyByte.length % base != 0) { int groups = keyByte.length / base + (keyB