18931165972

【石家庄小程序】后台解密用户数据

时间:2019-01-07

主页 > 新闻动态 > 公司动态 >

  石家庄微信小程序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;

  }

  2、解密工具类 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> 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?

  org.bouncycastle

  bcprov-ext-jdk16

  1.46

  jar

  compile

  这样才能引入bcprov这个jar包。网上参考了一下,个人感觉加这个依赖是最容易解决问题的。

上一篇:【石家庄小程序】如何显示群名称?

下一篇:没有了

转载注明出处:http://www.huazihai.cn/news/gs/107.html

Copyright © 2010-2018 花姿海 版权所有