微信公众平台是运营者通过公众号为微信用户提供资讯和服务的平台,而公众平台开发接口则是提供服务的基础。
接入微信公众平台开发,开发者需要按照如下步骤完成:
1、填写服务器配置
2、验证服务器地址的有效性
3、依据接口文档实现业务逻辑
以上步骤可在微信开发公众官方文档中查看 点击查看
下面主要说下开发过程中会接触到的一些问题。
1.微信接入问题
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序 2)将三个参数字符串拼接成一个字符串进行sha1加密 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 |
以上为官方文档内容,具体实现如下
1 @RequestMapping(value="/wechat.do",method = RequestMethod.GET) 2 public @ResponseBody String authGet(@RequestParam(value="signature",required=false) String signature, 3 @RequestParam("timestamp") String timestamp, 4 @RequestParam("nonce") String nonce, 5 @RequestParam("echostr") String echostr) throws Exception { 6 7 String sysytemAppid =(String)wxPropertiesBean.getProperties("system").get("system_appid"); 8 Map config = this.wxMpService.queryWxAccountByCode(sysytemAppid); 9 String token = (String) config.get("account_token"); 10 if (!WxCryptUtil.checkSignature(token,signature, timestamp, nonce)) { 11 logger.error("微信接入验证失败!"); 12 return null; 13 } 14 return echostr; 15 }
public static boolean checkSignature(String token, String signature, String timestamp, String nonce) { String[] arr = new String[] { token, timestamp, nonce }; Arrays.sort(arr); StringBuilder content = new StringBuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } MessageDigest md = null; String tmpStr = null; try { md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(content.toString().getBytes()); tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { } return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; } /** * 将字节数组转换为十六进制字符 * * @param byteArray * @return */ public static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * 将字节转换为十六进制字符 * * @param mByte * @return */ public static String byteToHexStr(byte mByte) { char[] Digit = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘, ‘A‘, ‘B‘, ‘C‘, ‘D‘, ‘E‘, ‘F‘ }; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s; }
2.获取access_token
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
接口调用请求说明
https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
grant_type | 是 | 获取access_token填写client_credential |
appid | 是 | 第三方用户唯一凭证 |
secret | 是 | 第三方用户唯一凭证密钥,即appsecret |
返回说明
正常情况下,微信会返回下述JSON数据包给公众号:
{"access_token":"ACCESS_TOKEN","expires_in":7200} |
参数说明
参数 | 说明 |
---|---|
access_token | 获取到的凭证 |
expires_in | 凭证有效时间,单位:秒 |
private String getAcessTokenEntity(Map accountConfig) { String requestUrl = (String) wxPropertiesBean.getProperties("wxpt").get("access_token_url"); Map urlParams = new HashMap(); urlParams.put("grant_type", "client_credential"); urlParams.put("appid", accountConfig.get("account_appid")); urlParams.put("secret", accountConfig.get("account_appsecret")); requestUrl = HttpUtil.getUrl(requestUrl, urlParams); try{ WxApiResult apiResult = HttpUtil.httpsRequest(requestUrl, "GET", null); Map result = HttpUtil.getCommonResult(apiResult); String accessToken = (String) result.get("access_token"); if(StringUtils.isBlank(accessToken)){ throw new WxErrorException("获取accessToken失败!"); } String accountId = (String) accountConfig.get("account_id"); wxMpService.updateAccessToken(accountId, accessToken); return accessToken; }catch (WxErrorException e){ throw e; }catch (Exception e){ logger.error(e.getMessage()); throw new WxErrorException("获取accessToken失败!"); } }
由于access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。我这里是将token落地在自己的库中,单独一张表用于记录和微信相关的所有的配置。
刷新token后再重新存入表中(包括存入时间记录),每次需要获取token的时候从表中获取,这样可以先判断是否过期,再决定是否需要重新获取。
未完待续,后面将介绍自定义菜单,oauth2认证等。