微信小程序后台解密用户数据


声明:本文转载自https://my.oschina.net/u/3396785/blog/1036381,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

微信小程序API文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html 
openId : 用户在当前小程序的唯一标识 
因为最近根据API调用https://api.weixin.qq.com/sns/jscode2session所以需要配置以下服务,但是官方是不赞成这种做法的, 
而且最近把在服务器配置的方法给关闭了。也就是说要获取用户openid,地区等信息只能在后台获取。 
一下是官方的流程

那么问题来了,代码怎么实现呢,以下是用java后台的实现

微信客户端的代码实现是这样的

[html] view plain copy print? 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

[java] view plain copy print? /**       * 解密用户敏感数据       *       * @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

[java] view plain copy print? 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 [java] view plain copy print? 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文件加上这个依赖

[java] view plain copy print? <dependency>       <groupId>org.bouncycastle</groupId>       <artifactId>bcprov-ext-jdk16</artifactId>       <version>1.46</version>       <type>jar</type>       <scope>compile</scope>   </dependency>   

这样才能引入bcprov这个jar包。网上参考了一下,个人感觉加这个依赖是最容易解决问题的。 
最近打算弄个关于微信运动的小程序,解密这块估计也要用到。大家有疑问可以一起留言交流

本文发表于2017年06月27日 10:36
(c)注:本文转载自https://my.oschina.net/u/3396785/blog/1036381,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2149 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1