当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 微信小程序后台解密用户数据实例详解

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

2017年12月12日  | 移动技术网IT编程  | 我要评论

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

微信小程序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包。网上参考了一下,个人感觉加这个依赖是最容易解决问题的。

最近打算弄个关于微信运动的小程序,解密这块估计也要用到。大家有疑问可以一起留言交流

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网