In diesem Artikel werden hauptsächlich relevante Informationen zu den detaillierten Beispielen für die Entschlüsselung von Benutzerdaten im Hintergrund des WeChat-Applets vorgestellt.
Detaillierte Erläuterungen zu den Beispielen für die Entschlüsselung von Benutzerdaten im Hintergrund des WeChat-Applets
openId: Die eindeutige Kennung des Benutzers im aktuellen Miniprogramm
Weil https://api.weixin.qq.com/sns /jscode2session wurde kürzlich gemäß der API aufgerufen, die folgenden Dienste müssen konfiguriert werden. Der Beamte stimmt diesem Ansatz jedoch nicht zu,
und vor kurzem wurde die Serverkonfigurationsmethode geschlossen. Mit anderen Worten: Informationen wie Benutzer-OpenID und Region können nur im Hintergrund abgerufen werden.
Dies ist der offizielle Prozess
Dann stellt sich die Frage, wie der Code implementiert wird. Das Folgende ist die Implementierung mit Java-Hintergrund
WeChat Die Client-Code-Implementierung lautet wie folgt
wx.login({ success: function (r) { if (r.code) { var code = r.code;//登录凭证 if (code) { //2、调用获取用户信息接口 wx.getUserInfo({ success: function (res) { //发起网络请求 wx.request({ url: that.data.net + '/decodeUser.json', header: { "content-type": "application/x-www-form-urlencoded" }, method: "POST", data: { encryptedData: res.encryptedData, iv: res.iv, code: code }, success: function (result) { // wx.setStorage({ // key: 'openid', // data: res.data.openid, // }) console.log(result) } }) }, fail: function () { console.log('获取用户信息失败') } }) } else { console.log('获取用户登录态失败!' + r.errMsg) } } else { } } })
(serverseitiges Java) Der eigene Server sendet den Code an den WeChat-Server, um openid (eindeutige Benutzeridentifikation) und session_key (Sitzungsschlüssel) zu erhalten,
Schließlich erhält encryptData, iv, session_key benutzersensible Daten durch AES-Entschlüsselung
1. Erhalten Sie den geheimen Schlüssel und verarbeiten Sie den entschlüsselten Controller
/** * 解密用户敏感数据 * * @param encryptedData 明文,加密数据 * @param iv 加密算法的初始向量 * @param code 用户允许登录后,回调内容会带上 code(有效期五分钟),开发者需要将 code 发送到开发者服务器后台,使用code 换取 session_key api,将 code 换成 openid 和 session_key * @return */ @ResponseBody @RequestMapping(value = "/decodeUser", method = RequestMethod.POST) public Map decodeUser(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 = "wxd8980e77d335c871"; //小程序的 app secret (在微信小程序管理后台获取) String wxspSecret = "85d29ab4fa8c797423f2d7da5dd514cf"; //授权(必填) 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.fromObject(sr); //获取会话密钥(session_key) String session_key = json.get("session_key").toString(); //用户的唯一标识(openid) String openid = (String) json.get("openid"); //////////////// 2、对encryptedData加密数据进行AES解密 //////////////// try { String result = AesCbcUtil.decrypt(encryptedData, session_key, iv, "UTF-8"); if (null != result && result.length() > 0) { map.put("status", 1); map.put("msg", "解密成功"); JSONObject userInfoJSON = JSONObject.fromObject(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; }
Entschlüsselungs-Tool-Klasse AesCbcUtil
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; /** * Created by lsh * AES-128-CBC 加密方式 * 注: * AES-128-CBC可以自己定义“密钥”和“偏移量“。 * AES-128是jdk自动生成的“密钥”。 */ public class AesCbcUtil { 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 { // initialize(); //被加密的数据 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; } }
Tool-Klasse zum Senden von Anfragen HttpRequest
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.util.List; import java.util.Map; /** * Created by lsh on 2017/6/22. */ public class HttpRequest { /** * 向指定URL发送GET方法的请求 * * @param url * 发送请求的URL * @param param * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return URL 所代表远程资源的响应结果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立实际的连接 connection.connect(); // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader( connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 发送POST方法的请求 * * @param url * 发送请求的 URL * @param param * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送 POST 请求出现异常!"+e); e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result; } }
Darüber hinaus ist dies aufgrund der Notwendigkeit, die Entschlüsselungs-Tool-Klasse zu verwenden Abhängigkeit muss zur POM-Datei hinzugefügt werden
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-ext-jdk16</artifactId> <version>1.46</version> <type>jar</type> <scope>compile</scope> </dependency>
Auf diese Weise kann das bcprov-JAR-Paket eingeführt werden. Nach einigen Online-Referenzen bin ich persönlich der Meinung, dass das Hinzufügen dieser Abhängigkeit der einfachste Weg ist, das Problem zu lösen.
Das obige ist der detaillierte Inhalt vonBeispiel für die Freigabe der Entschlüsselung von Benutzerdaten im Hintergrund des WeChat-Applets. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!