解密流程
代码实现
小程序客户端
wx.login({ // 获取code success: function (res) { //用拿到的code,从后台获取sessionId wx.request({ url: sessionID, method: 'GET', data: { js_code: res.code, movieCode: movieCode }, header: { "Content-Type": "application/x-www-form-urlencoded", 'Accept': 'application/json' }, success: function (res) { //从后台获取到的sessionId var sessionId = res.data.resultData; wx.setStorageSync('sessionId', sessionId); //获取加密数据encryptedData wx.getUserInfo({ success: function(msg){ var encryptedData = msg.encryptedData, iv = msg.iv; //发起解密请求 wx.request({ url: userInfoUrl, method: 'POST', data: { encryptedData: encryptedData, iv: iv, sessionId: sessionId }, header: { "Content-Type": "application/x-www-form-urlencoded", 'Accept': 'application/json' }, success: function (res) { console.log(res, 1234); var data = JSON.parse(res.data.resultData), resultCode = res.data.resultCode, resultDesc = res.data.resultDesc; } }) } }); } });服务端(Java)
- 服务端获取sessionId
/** * 初始化微信小程序参数 * @param request * @param js_code 登录时获取的 code * @return */ @ResponseBody @RequestMapping("/initWxLogin") public Result initWxLogin(HttpServletRequest request, @RequestParam(value="js_code",required = true)String js_code, @RequestParam(value="movieCode",required = true)String movieCode){ logger.info("开始执行请求初始化微信小程序参数:/initWxLogin"); Result result = new Result(); MapString,String params = new HashMap(); MovieCompany company = new MovieCompany(); company.setCompanyCode(movieCode); ListMovieCompany companies = movieCompanyService.getCompanyInfo(company); CinemaPay cinemaPay = cinemaPayService.queryCinemaPayByCompanyCode(movieCode,"5"); if(companies == null || companies.size() == 0){ result.setResultDesc("院线信息不正确"); result.setResultCode(Constants.Result_Error_Code_500); return result; } params.put("appid", cinemaPay.getWechatAppId()); params.put("secret",cinemaPay.getWechatDecodeAppSecret()); params.put("js_code",js_code); params.put("grant_type","authorization_code"); String resultData = HttpUtils.doPost(wxLoginUrl, params, "UTF-8"); MapString,Object data = JsonMapper.getInstance().fromJson(resultData,Map.class); String cacheKey = IdUtils.getRandomByUUId(); String openid ; if(data!=null){ if(null!=data.get("openid")) { //正常返回的JSON数据包 openid = data.get("openid").toString(); String sessionKey = data.get("session_key").toString(); String val = sessionKey+"#"+openid; result.setResultData(cacheKey); redis.set(cacheKey,val,60*5); } else { result.setResultData(resultData); result.setResultCode(Constants.Result_Error_Code_500); } } return result; }- 解密实现
/** * 解密小程序用户敏感数据 * @param encryptedData 明文 * @param iv 加密算法的初始向量 * @param sessionId 会话ID * @return */ @ResponseBody @RequestMapping(value = "/decodeUserInfo") public Result decodeUserInfo(@RequestParam(required = true,value = "encryptedData")String encryptedData, @RequestParam(required = true,value = "iv")String iv, @RequestParam(required = true,value = "sessionId")String sessionId){ logger.info("开始执行请求解密小程序用户敏感数据:/decodeUserInfo"); Result result= new Result(); //从缓存中获取session_key String wxSessionObj = redis.get(sessionId,String.class); if(StringUtils.isEmpty(wxSessionObj)){ result.setResultCode(Constants.Result_Error_Code_500); result.setResultDesc("sessionId不存在"); return result; } String wxSessionStr = (String)wxSessionObj; String sessionKey = wxSessionStr.split("#")[0]; try { AESUtils aes = new AESUtils(); byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv)); if(null != resultByte && resultByte.length 0){ String userInfo = new String(resultByte, "UTF-8"); result.setResultData(userInfo); return result; } } catch (UnsupportedEncodingException e) { e.printStackTrace(); result.setResultCode(Constants.Result_Error_Code_500); result.setResultDesc("获取用户解密信息失败"); } catch (InvalidAlgorithmParameterException e) { result.setResultCode(Constants.Result_Error_Code_500); result.setResultDesc("获取用户解密信息失败"); e.printStackTrace(); } return result; }- AES解密
public static boolean initialized = false; /** * AES解密 * @param content 密文 * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchProviderException */ public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException { initialize(); try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); Key sKeySpec = new SecretKeySpec(keyByte, "AES"); cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化 byte[] result = cipher.doFinal(content); return result; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public static void initialize(){ if (initialized) return; Security.addProvider(new BouncyCastleProvider()); initialized = true; } //生成iv public static AlgorithmParameters generateIV(byte[] iv) throws Exception { AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); params.init(new IvParameterSpec(iv)); return params; }结语
总体思路就是,小程序客户端调用微信服务器接口,获取code、加密数据encryptedData,以及偏移向量iv;然后将code发送到开发者服务器,开发者服务器通过code换取秘钥session_key和openId,并返回到开发者服务器,然后开发者服务器生成sessonId,以sessionId为key,session_key和openId为value,存入缓存,并将sessionId返回到小程序客户端。然后小程序客户端将sessionId、wncrypteddata、iv发送到开发者服务器进行解密。













