• 微信小程序:java后台获取openId


    一、功能描述

    openId是某个微信账户对应某个小程序或者公众号的唯一标识,但openId必须经过后台解密才能获取(之前实现过前台解密,可是由于微信小程序的种种限制,前台解密无法在小程序发布后使用)

    二、实现流程

    1. 获取微信用户的登录信息;

    2. 将encryptedData中的数据作为参数传给java后台

    3. java后台进行解密

    三、代码实现

    1. 后台的解密代码

     1 /**
     2      * decoding encrypted data to get openid
     3      *
     4      * @param iv
     5      * @param encryptedData
     6      * @param code
     7      * @return
     8      */
     9     @RequestMapping(value = "/decodeUserInfo", method = RequestMethod.GET)
    10     private Map decodeUserInfo(String iv, String encryptedData, String code) {
    11         Map map = new HashMap();
    12         // login code can not be null
    13         if (code == null || code.length() == 0) {
    14             map.put("status", 0);
    15             map.put("msg", "code 不能为空");
    16             return map;
    17         }
    18         // mini-Program's AppID
    19         String wechatAppId = "你的小程序的AppID";
    20 
    21         // mini-Program's session-key
    22         String wechatSecretKey = "你的小程序的session-key";
    23 
    24         String grantType = "authorization_code";
    25 
    26         // using login code to get sessionId and openId
    27         String params = "appid=" + wechatAppId + "&secret=" + wechatSecretKey + "&js_code=" + code + "&grant_type=" + grantType;
    28 
    29         // sending request
    30         String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
    31 
    32         // analysis request content
    33         JSONObject json = JSONObject.fromObject(sr);
    34 
    35         // getting session_key
    36         String sessionKey = json.get("session_key").toString();
    37 
    38         // getting open_id
    39         String openId = json.get("openid").toString();
    40 
    41         // decoding encrypted info with AES
    42         try {
    43             String result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, "UTF-8");
    44             if (null != result && result.length() > 0) {
    45                 map.put("status", 1);
    46                 map.put("msg", "解密成功");
    47 
    48                 JSONObject userInfoJSON = JSONObject.fromObject(result);
    49                 Map userInfo = new HashMap();
    50                 userInfo.put("openId", userInfoJSON.get("openId"));
    51                 userInfo.put("nickName", userInfoJSON.get("nickName"));
    52                 userInfo.put("gender", userInfoJSON.get("gender"));
    53                 userInfo.put("city", userInfoJSON.get("city"));
    54                 userInfo.put("province", userInfoJSON.get("province"));
    55                 userInfo.put("country", userInfoJSON.get("country"));
    56                 userInfo.put("avatarUrl", userInfoJSON.get("avatarUrl"));
    57                 userInfo.put("unionId", userInfoJSON.get("unionId"));
    58                 map.put("userInfo", userInfo);
    59                 return map;
    60             }
    61 
    62 
    63         } catch (Exception e) {
    64             e.printStackTrace();
    65         }
    66         map.put("status", 0);
    67         map.put("msg", "解密失败");
    68         return map;
    69     }

    2. 前台代码

     1 wx.login({
     2       success: function (res) {
     3         that.globalData.code = res.code;//登录凭证
     4         if (that.globalData.code) {
     5           //2、调用获取用户信息接口
     6           // 查看是否授权
     7           wx.getUserInfo({
     8             success: function (res) {
     9               that.globalData.encryptedData = res.encryptedData
    10               that.globalData.iv = res.iv
    11               console.log('[INFO] app.js/ ',{ encryptedData: res.encryptedData, iv: res.iv, code: that.globalData.code })
    12               //3.请求自己的服务器,解密用户信息 获取unionId等加密信息
    13               wx.request({
    14                 url: 'https://www.****.cn/***/****/decodeUserInfo',//自己的服务接口地址
    15                 method: 'get',
    16                 header: {
    17                   "Content-Type": "applciation/json"
    18                 },
    19                 data: { encryptedData: res.encryptedData, iv: res.iv, code: that.globalData.code },
    20                 success: function (data) {
    21 
    22                   //4.解密成功后 获取自己服务器返回的结果
    23                   if (data.data.status == 1) {
    24                     var userInfos = data.data.userInfo;
    25                     that.globalData.openId = userInfos.openId;
    26                     console.log('[INFO] app.js/ userInfo:',userInfos)
    27                   } else {
    28                     console.log('[INFO] app.js/ 解密失败')
    29                   }
    30                 },
    31                 fail: function () {
    32                   console.log('[INFO] app.js/ 系统错误')
    33                 }
    34               })
    35             },
    36             fail: function () {
    37               console.log('[INFO] app.js/ 获取用户信息失败')
    38             }
    39           })
    40         } else {
    41           console.log('[INFO] app.js/ 获取用户登录态失败!' + r.errMsg)
    42         }
    43       },
    44       fail: function () {
    45         console.log('[INFO] app.js/ 登陆失败')
    46       }
    47     })
    48 
    49     // 获取用户信息
    50     wx.getSetting({
    51       success: res => {
    52         if (res.authSetting['scope.userInfo']) {
    53           // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
    54           wx.getUserInfo({
    55             success: res => {
    56               // 可以将 res 发送给后台解码出 unionId
    57               this.globalData.userInfo = res.userInfo;
    58 
    59               // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
    60               // 所以此处加入 callback 以防止这种情况
    61               if (this.userInfoReadyCallback) {
    62                 this.userInfoReadyCallback(res)
    63               }
    64             }
    65           })
    66         }
    67       }
    68     })
    69   },

    2. HttpRequest工具类

      1 import java.io.BufferedReader;
      2 import java.io.IOException;
      3 import java.io.InputStreamReader;
      4 import java.io.PrintWriter;
      5 import java.net.URL;
      6 import java.net.URLConnection;
      7 import java.util.List;
      8 import java.util.Map;
      9 
     10 public class HttpRequest {
     11 
     12     public static void main(String[] args) {
     13         //发送 GET 请求
     14         String s=HttpRequest.sendGet("http://v.qq.com/x/cover/kvehb7okfxqstmc.html?vid=e01957zem6o", "");
     15         System.out.println(s);
     16 
     17 //        //发送 POST 请求
     18 //        String sr=HttpRequest.sendPost("http://www.toutiao.com/stream/widget/local_weather/data/?city=%E4%B8%8A%E6%B5%B7", "");
     19 //        JSONObject json = JSONObject.fromObject(sr);
     20 //        System.out.println(json.get("data"));
     21     }
     22 
     23     /**
     24      * 向指定URL发送GET方法的请求
     25      *
     26      * @param url
     27      *            发送请求的URL
     28      * @param param
     29      *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     30      * @return URL 所代表远程资源的响应结果
     31      */
     32     public static String sendGet(String url, String param) {
     33         String result = "";
     34         BufferedReader in = null;
     35         try {
     36             String urlNameString = url + "?" + param;
     37             URL realUrl = new URL(urlNameString);
     38             // 打开和URL之间的连接
     39             URLConnection connection = realUrl.openConnection();
     40             // 设置通用的请求属性
     41             connection.setRequestProperty("accept", "*/*");
     42             connection.setRequestProperty("connection", "Keep-Alive");
     43             connection.setRequestProperty("user-agent",
     44                     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
     45             // 建立实际的连接
     46             connection.connect();
     47             // 获取所有响应头字段
     48             Map<String, List<String>> map = connection.getHeaderFields();
     49             // 遍历所有的响应头字段
     50             for (String key : map.keySet()) {
     51                 System.out.println(key + "--->" + map.get(key));
     52             }
     53             // 定义 BufferedReader输入流来读取URL的响应
     54             in = new BufferedReader(new InputStreamReader(
     55                     connection.getInputStream()));
     56             String line;
     57             while ((line = in.readLine()) != null) {
     58                 result += line;
     59             }
     60         } catch (Exception e) {
     61             System.out.println("发送GET请求出现异常!" + e);
     62             e.printStackTrace();
     63         }
     64         // 使用finally块来关闭输入流
     65         finally {
     66             try {
     67                 if (in != null) {
     68                     in.close();
     69                 }
     70             } catch (Exception e2) {
     71                 e2.printStackTrace();
     72             }
     73         }
     74         return result;
     75     }
     76 
     77     /**
     78      * 向指定 URL 发送POST方法的请求
     79      *
     80      * @param url
     81      *            发送请求的 URL
     82      * @param param
     83      *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     84      * @return 所代表远程资源的响应结果
     85      */
     86     public static String sendPost(String url, String param) {
     87         PrintWriter out = null;
     88         BufferedReader in = null;
     89         String result = "";
     90         try {
     91             URL realUrl = new URL(url);
     92             // 打开和URL之间的连接
     93             URLConnection conn = realUrl.openConnection();
     94             // 设置通用的请求属性
     95             conn.setRequestProperty("accept", "*/*");
     96             conn.setRequestProperty("connection", "Keep-Alive");
     97             conn.setRequestProperty("user-agent",
     98                     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
     99             // 发送POST请求必须设置如下两行
    100             conn.setDoOutput(true);
    101             conn.setDoInput(true);
    102             // 获取URLConnection对象对应的输出流
    103             out = new PrintWriter(conn.getOutputStream());
    104             // 发送请求参数
    105             out.print(param);
    106             // flush输出流的缓冲
    107             out.flush();
    108             // 定义BufferedReader输入流来读取URL的响应
    109             in = new BufferedReader(
    110                     new InputStreamReader(conn.getInputStream()));
    111             String line;
    112             while ((line = in.readLine()) != null) {
    113                 result += line;
    114             }
    115         } catch (Exception e) {
    116             System.out.println("发送 POST 请求出现异常!"+e);
    117             e.printStackTrace();
    118         }
    119         //使用finally块来关闭输出流、输入流
    120         finally{
    121             try{
    122                 if(out!=null){
    123                     out.close();
    124                 }
    125                 if(in!=null){
    126                     in.close();
    127                 }
    128             }
    129             catch(IOException ex){
    130                 ex.printStackTrace();
    131             }
    132         }
    133         return result;
    134     }
    135 }

    3. AesCbuUtil工具类

     1 import org.apache.commons.codec.binary.Base64;
     2 import org.bouncycastle.jce.provider.BouncyCastleProvider;
     3 
     4 import javax.crypto.BadPaddingException;
     5 import javax.crypto.Cipher;
     6 import javax.crypto.IllegalBlockSizeException;
     7 import javax.crypto.NoSuchPaddingException;
     8 import javax.crypto.spec.IvParameterSpec;
     9 import javax.crypto.spec.SecretKeySpec;
    10 import java.io.UnsupportedEncodingException;
    11 import java.security.*;
    12 import java.security.spec.InvalidParameterSpecException;
    13 
    14 public class AesCbcUtil {
    15 
    16     static {
    17         //BouncyCastle是一个开源的加解密解决方案,主页在http://www.bouncycastle.org/
    18         Security.addProvider(new BouncyCastleProvider());
    19     }
    20 
    21     /**
    22      * AES解密
    23      *
    24      * @param data           //密文,被加密的数据
    25      * @param key            //秘钥
    26      * @param iv             //偏移量
    27      * @param encodingFormat //解密后的结果需要进行的编码
    28      * @return
    29      * @throws Exception
    30      */
    31     public static String decrypt(String data, String key, String iv, String encodingFormat) throws Exception {
    32 //        initialize();
    33 
    34         //被加密的数据
    35         byte[] dataByte = Base64.decodeBase64(data.getBytes());
    36         //加密秘钥
    37         byte[] keyByte = Base64.decodeBase64(key.getBytes());
    38         //偏移量
    39         byte[] ivByte = Base64.decodeBase64(iv.getBytes());
    40 
    41 
    42         try {
    43             Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    44 
    45             SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
    46 
    47             AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
    48             parameters.init(new IvParameterSpec(ivByte));
    49 
    50             cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
    51 
    52             byte[] resultByte = cipher.doFinal(dataByte);
    53             if (null != resultByte && resultByte.length > 0) {
    54                 String result = new String(resultByte, encodingFormat);
    55                 return result;
    56             }
    57             return null;
    58         } catch (NoSuchAlgorithmException e) {
    59             e.printStackTrace();
    60         } catch (NoSuchPaddingException e) {
    61             e.printStackTrace();
    62         } catch (InvalidParameterSpecException e) {
    63             e.printStackTrace();
    64         } catch (InvalidKeyException e) {
    65             e.printStackTrace();
    66         } catch (InvalidAlgorithmParameterException e) {
    67             e.printStackTrace();
    68         } catch (IllegalBlockSizeException e) {
    69             e.printStackTrace();
    70         } catch (BadPaddingException e) {
    71             e.printStackTrace();
    72         } catch (UnsupportedEncodingException e) {
    73             e.printStackTrace();
    74         }
    75 
    76         return null;
    77     }
    78 
    79 }
  • 相关阅读:
    mysql cpu 占用高
    使用cron命令配置定时任务(cron jobs)
    python 获取时间
    linux 免密码登陆
    linux 查看登录日志
    shizhong
    正则(?is)
    python shell
    linux 时间设置
    java获取当前时间前一周、前一月、前一年的时间
  • 原文地址:https://www.cnblogs.com/huiAlex/p/9463181.html
Copyright © 2020-2023  润新知