微信小程序后台解密用户数据实例详解
程序员文章站
2023-09-08 21:47:21
微信小程序后台解密用户数据实例详解
微信小程序api文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-...
微信小程序后台解密用户数据实例详解
微信小程序api文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html
openid : 用户在当前小程序的唯一标识
因为最近根据api调用https://api.weixin.qq.com/sns/jscode2session所以需要配置以下服务,但是官方是不赞成这种做法的,
而且最近把在服务器配置的方法给关闭了。也就是说要获取用户openid,地区等信息只能在后台获取。
一下是官方的流程
那么问题来了,代码怎么实现呢,以下是用java后台的实现
微信客户端的代码实现是这样的
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 { } } })
(服务端 java)自己的服务器发送code到微信服务器获取openid(用户唯一标识)和session_key(会话密钥),
最后将encrypteddata、iv、session_key通过aes解密获取到用户敏感数据
1、获取秘钥并处理解密的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; }
解密工具类 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; } }
发送请求的工具类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; } }
另外由于需求使用解密的工具类所有要在pom文件加上这个依赖
<dependency> <groupid>org.bouncycastle</groupid> <artifactid>bcprov-ext-jdk16</artifactid> <version>1.46</version> <type>jar</type> <scope>compile</scope> </dependency>
这样才能引入bcprov这个jar包。网上参考了一下,个人感觉加这个依赖是最容易解决问题的。
最近打算弄个关于微信运动的小程序,解密这块估计也要用到。大家有疑问可以一起留言交流
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
上一篇: 微信小程序之网络请求简单封装实例详解
下一篇: JavaScript中常见的八个陷阱总结