1. 程式人生 > >微信小程序:java後臺獲取openId

微信小程序:java後臺獲取openId

+= rspec post main 接口 common https output rgs

一、功能描述

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 }

微信小程序:java後臺獲取openId