1、思路图解
2、思路描述
(1)小程序调用wx.login获取code
(2)小程序调用wx.getUserInfo得到rawData, signatrue, encryptData.
(3)小程序调用Server并传入前两步获取的code、rawData、signature、encryptData,server调用微信提供的jsoncode2session接口获取openid、sessionKey
(4)签名验证signature
(5)利用(3)获取的sessionKey解密entryptData,验证openid是否对应
3、代码展示
(1)接口(此处PageData可等同于request.getParameter)
@RequestMapping(value = "/login") @ResponseBody public Object login() throws Exception { logger.info("Start getSessionKey"); JsonResult jsonResult = new JsonResult(); String code = MessageUtil.CODE_SUCCESS;//状态码 String msg = MessageUtil.MSG_00;//提示信息 PageData pd = new PageData(); try { pd = this.getPageData(); PageData data = new PageData(); String token = ""; if(!pd.containsKey("code") || StringUtils.isEmpty(pd.getString("code"))){ code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_NULL; }else if(!pd.containsKey("rawData") || StringUtils.isEmpty(pd.getString("rawData"))){ code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_NULL; }else if(!pd.containsKey("signature") || StringUtils.isEmpty(pd.getString("signature"))){ code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_NULL; }else if(!pd.containsKey("encryptedData") || StringUtils.isEmpty(pd.getString("encryptedData"))){ code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_NULL; }else if(!pd.containsKey("iv") || StringUtils.isEmpty(pd.getString("iv"))){ code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_NULL; }else { String sessionKey = ""; String openId = ""; String unionId = ""; String sessionId = ""; String js_code = pd.getString("code"); String rawData = pd.getString("rawData"); String signature = pd.getString("signature"); String encryptedData = pd.getString("encryptedData"); String iv = pd.getString("iv"); System.out.println(js_code); System.out.println(rawData); System.out.println(signature); System.out.println(encryptedData); System.out.println(iv); String url = WXTools.LOGIN_CHECK_URL+"?appid=" + WXTools.APPID + "&secret=" + WXTools.SECRET + "&js_code=" + js_code + "&grant_type=" + WXTools.GRANT_TYPE; JSONObject object = CommonUtil.httpsRequest(url,"GET",null); if(object.has("session_key") && object.has("openid") && object.has("unionid")){ sessionKey = object.getString("session_key"); openId = object.getString("openid"); unionId = object.getString("unionid"); String sha1 = rawData + sessionKey; String sinature2 = WXUtils.getSha1(sha1); if(signature.equals(sinature2)){//签名验证 JSONObject info = WXUtils.getUserInfo(encryptedData,sessionKey,iv); if(info.has("unionId") && info.getString("unionId").equals(unionId)){ JSONObject watermark = info.getJSONObject("watermark"); PageData user = userService.handleLogin(info,unionId); Long timestamp = watermark.getLong("timestamp"); CacheEntity cacheEntity = new CacheEntity(); cacheEntity.setTimestap(timestamp); cacheEntity.setDatas(user); cacheEntity.setSessionKey(sessionKey); sessionId = this.getHttpSession().getId(); CacheManager cacheManager = new CacheManager(); cacheManager.putCache(sessionId,cacheEntity); token = AesTool.Encrypt(sessionId+","+openId+","+ UuidUtil.get6Number(),sessionKey); data.put("token",token); data.put("sessionId",sessionId); code = MessageUtil.CODE_SUCCESS; msg = MessageUtil.MSG_00; }else { code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_01; } }else { code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_01; } }else { code = MessageUtil.CODE_ERROR; msg = MessageUtil.MSG_01; } } jsonResult.setCode(code); jsonResult.setMessage(msg); jsonResult.setData(data); }catch (Exception e){ jsonResult.setCode(MessageUtil.CODE_ERROR); jsonResult.setMessage(MessageUtil.MSG_01); logger.error("getPlaceList [error] " + e.getMessage(), e); } return jsonResult; }
(2)发送微信请求工具类
public class CommonUtil { private static Logger log = LoggerFactory.getLogger(CommonUtil.class); /** * 发送https请求 * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod(requestMethod); // 当outputStr不为null时向输出流写数据 if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意编码格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 从输入流读取返回内容 InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("连接超时:{}", ce); } catch (Exception e) { log.error("https请求异常:{}", e); } return jsonObject; } }
(3)sinature以及解密encryptData工具
public class WXUtils { public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv){ // 被加密的数据 byte[] dataByte = Base64.decode(encryptedData); // 加密秘钥 byte[] keyByte = Base64.decode(sessionKey); // 偏移量 byte[] ivByte = Base64.decode(iv); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16; if (keyByte.length % base != 0) { int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyByte, 0, temp, 0, keyByte.length); keyByte = temp; } // 初始化 Security.addProvider(new BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC"); 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, "UTF-8"); return JSONObject.fromObject(result); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidParameterSpecException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { e.printStackTrace(); } return null; } public static String getSha1(String str){ if(StringUtils.isEmpty(str)){ return null; } char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f'}; try { MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); mdTemp.update(str.getBytes("UTF-8")); byte[] md = mdTemp.digest(); int j = md.length; char buf[] = new char[j*2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; buf[k++] = hexDigits[byte0 & 0xf]; } return new String(buf); }catch (Exception e){ return null; } } }
4、token前后台加密校验根据个人特长封装吧,或者查看本人博客Aes加密解密简单处理