Maison  >  Article  >  Applet WeChat  >  Exemple de partage de décryptage des données utilisateur en arrière-plan de l'applet WeChat

Exemple de partage de décryptage des données utilisateur en arrière-plan de l'applet WeChat

黄舟
黄舟original
2018-05-15 11:03:483132parcourir

Cet article présente principalement les informations pertinentes sur les exemples détaillés de décryptage des données utilisateur en arrière-plan de l'applet WeChat. Les amis dans le besoin peuvent se référer à

Explication détaillée des exemples de décryptage des données utilisateur. en arrière-plan de l'applet WeChat

openId : L'identifiant unique de l'utilisateur dans le mini programme actuel

Parce que https://api.weixin.qq.com/sns /jscode2session a été récemment appelé selon l'API, les services suivants doivent être configurés, cependant, le responsable n'approuve pas cette approche,
et récemment, la méthode de configuration du serveur a été fermée. C'est-à-dire que pour obtenir l'OpenID de l'utilisateur, la région et d'autres informations ne peuvent être obtenues qu'en arrière-plan.

C'est le processus officiel

Ensuite, la question est de savoir comment implémenter le code, voici l'implémentation en utilisant l'arrière-plan Java

WeChat L'implémentation du code client est la suivante

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 côté serveur) Le propre serveur envoie le code au serveur WeChat pour obtenir openid (identification unique de l'utilisateur) et session_key (clé de session),
Enfin, selectedData , iv, session_key obtient les données sensibles de l'utilisateur via le décryptage AES

1 Obtenez la clé secrète et traitez le contrôleur déchiffré

/** 
   * 解密用户敏感数据 
   * 
   * @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; 
  }

Classe d'outils de décryptage 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; 
  } 

}
Classe d'outils pour envoyer des requêtes 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; 
  } 
}
De plus, en raison de la nécessité d'utiliser la classe d'outils de décryptage, ceci la dépendance doit être ajoutée au fichier pom

<dependency> 
  <groupId>org.bouncycastle</groupId> 
  <artifactId>bcprov-ext-jdk16</artifactId> 
  <version>1.46</version> 
  <type>jar</type> 
  <scope>compile</scope> 
</dependency>
De cette façon, le package jar bcprov peut être introduit. Après quelques références en ligne, je pense personnellement que l'ajout de cette dépendance est le moyen le plus simple de résoudre le problème.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn