微信开放平台之第三方平台开发之流程攻略
大家好,我是小悟
不管是自己在创业或学习也好,还是公司的开发任务也罢,有很多小伙伴在开发多小程序管理或多公众号管理的功能,这就不得不去对接微信开放平台里面的第三方平台接口。
你别说,这个功能确实好用,我们就拿代商家管理小程序来说,对于有批量孵化小程序需求的业务来说,拥有了这样的功能,能节省不少成本嘞。除了这个,关键还有一个好处,就是只需收集极少数个参数信息,通过接口注册很多个已认证的小程序,目前没有上限的限制。注意,是已认证的,也就是免认证费的,还是永久的哦。
在看官方文档之前,你可能会想,接口嘛,对我们后端同学来说,我们就是专门造接口的,开什么玩笑,根本不在话下。不过,当你去翻了接口文档之后你就不会有这么嚣张的想法了,来,简单瞜一眼,
接口多的很,多也就算了,关键看不懂,不知道先从哪里入手啊。插一句,其实现在再去看官方文档,已经整理的更整洁了,比起我对接的那会啊,不知道好多少,我对接的那时候文档可以用杂乱无章来形容不为过,没办法,人总要成长,接口文档也是。
扯远了,文档确实变好了,但对于新手来说第一次看还是一头雾水,真的是不知道该从哪里入手啊。最重要的其实就是获取到component_access_token和授权帐号的authorizer_access_token,别担心,悟空帮你理一下如何入手,按照如下顺序进行开发。
【验证票据】:首先就是验证票据,也就是这个component_verify_ticket,在第三方平台创建审核通过后,微信服务器会向其 ”授权事件接收URL” 每隔 10 分钟以 POST 的方式推送 component_verify_ticket。
public void saveTicket(HttpServletRequest request, HttpServletResponse response) throws IOException {
String msgSignature = request.getParameter("msg_signature");// 微信加密签名
String timeStamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce"); // 随机数
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
StringBuffer sb = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
sb = sb.append(line);
}
String postData = sb.toString();
try {
AuthorizedUtils.saveComponentVerifyTicket(msgSignature, timeStamp, nonce, postData);
} catch (Exception e) {
logger.error("系统异常", e);
} finally {
// 响应消息
PrintWriter out = response.getWriter();
out.print("success");
}
}
这个不是API接口,是微信主动向我们的服务器推送的一个参数数据。至于第三方平台怎么配置,这个应该不难,如果不会的同学多了,以后就抽空写一篇介绍一下怎么配置。
【获取令牌】:我们拿到component_verify_ticket之后,接着就要去调用获取令牌的接口,获取到第三方平台接口的调用凭据component_access_token的值。令牌的获取是有限制的,每个令牌的有效期为 2 小时,请自行做好令牌的管理,在令牌快过期时(比如1小时50分),重新调用接口获取。
public static ComponentToken getComponentToken(String ticket) {
RedisService<ComponentToken> redisService = RedisService.load();
ComponentToken componentToken = redisService.load(ComponentToken.COMPONENTTOKEN_ID, ComponentToken.class);
if (componentToken == null) {
String encryptAppId = ThirdPlat.PLAT_APPID;
String appId = EnDecryptUtil.d3esDecode(encryptAppId);
String encryptSecret = ThirdPlat.PLAT_SECRET;
String secret = EnDecryptUtil.d3esDecode(encryptSecret);
String requestUrl = AuthAccessUrl.COMPONENT_ACCESS_URL;
Map<String, String> map = new HashMap<>();
map.put("component_appid", appId); //第三方平台appid
map.put("component_appsecret", secret); //第三方平台appsecret
map.put("component_verify_ticket", ticket);
String outputStr = JSONObject.toJSONString(map);
logger.warn("请求数据"+outputStr);
JSONObject jsonObject = HttpRequestUtils.httpRequest(requestUrl, "POST", outputStr);
if (null != jsonObject) {
long expires = System.currentTimeMillis() + 7200;
try{
expires = System.currentTimeMillis() + jsonObject.getIntValue("expires_in");
}catch (Exception e) {
}
try {
componentToken = new ComponentToken();
componentToken.setComponentAccessToken(jsonObject.getString("component_access_token"));
componentToken.setExpiresIn(expires);
redisService.save(componentToken, ComponentToken.class);
} catch (Exception e) {
componentToken = null;
logger.error("系统异常", e);
}
}
} else {
long sysTime = System.currentTimeMillis();
if (sysTime >= componentToken.getExpiresIn()) {
redisService.delete(ComponentToken.COMPONENTTOKEN_ID, ComponentToken.class);
componentToken = getComponentToken(ticket);
}else{
}
}
return componentToken;
}
【获取预授权码】:我们拿到component_access_token之后,接着就要去调用获取预授权码的接口,获取到pre_auth_code的值。这个是第三方平台方实现授权托管的必备信息,每个预授权码有效期为 1800秒。
public static String getPreAuthCode(String ticket) {
ComponentToken componentToken = getComponentToken(ticket);
String encryptAppId = ThirdPlat.PLAT_APPID;
String appId = EnDecryptUtil.d3esDecode(encryptAppId);
String url = AuthAccessUrl.PRE_AUTH_CODE_URL + componentToken.getComponentAccessToken();
Map<String, String> map = new HashMap<String, String>();
map.put("component_appid", appId);
JSONObject jsonObject = HttpRequestUtils.httpRequest(url, "POST", JSONObject.toJSONString(map));
return jsonObject.getString("pre_auth_code");
}
【拼接授权链接】:我们拿到pre_auth_code之后,这一步不需要调用接口,而是拼接授权链接。准备“授权回调 URI”,公众号/小程序管理员扫码或者访问移动端授权链接,确认同意授权给第三方平台。管理员授权确认之后,授权页会自动跳转进入回调 URI,并在 URL 参数中返回授权码和过期时间(redirect_url?auth_code=xxx&expires_in=600)。
public AjaxResult getMchWebAuthUrl(@PathVariable("id") String id) {
RedisService<ComponentVerifyTicket> redisService = RedisService.load();
ComponentVerifyTicket componentVerifyTicket = redisService.load(ComponentVerifyTicket.COMPONENT_VERIFY_TICKET_ID,
ComponentVerifyTicket.class);
if(componentVerifyTicket == null){
return AjaxResult.error("引入用户进入授权页失败,component_verify_ticket为null",null);
}else{
String preAuthCode = AuthorizedUtils.getPreAuthCode(componentVerifyTicket.getComponentVerifyTicket());
String encryptAppId = ThirdPlat.PLAT_APPID;
String appId = EnDecryptUtil.d3esDecode(encryptAppId);
String auth_type = ThirdPlat.AUTH_TYPE;
String requestUrl = AuthAccessUrl.WEB_AUTH_URL;
try {
requestUrl = requestUrl.replace("COMPONENT_APPID", appId).replace("PRE_AUTH_CODE", preAuthCode)
.replace("REDIRECT_URI", URLEncoder.encode(ThirdPlat.REDIRECT_URI.replace("MERCHANTID", id),"UTF-8")).replace("AUTH_TYPE", auth_type);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return AjaxResult.success("操作成功",requestUrl);
}
}
【获取刷新令牌】:我们拿到auth_code之后,接着就要去调用获取刷新令牌的接口,当用户在第三方平台授权页中完成授权流程后,第三方平台开发者可以在回调 URI 中通过 URL 参数获取授权码(authorization_code)。然后使用该接口可以换取公众号/小程序的接口调用令牌(authorizer_access_token),然后以该 token 调用公众号或小程序的相关 API。
public static AuthorizationInfo initAuthorizationInfo(String code) {
RedisService<ComponentVerifyTicket> redisService = RedisService.load();
ComponentVerifyTicket componentVerifyTicket = redisService.load(ComponentVerifyTicket.COMPONENT_VERIFY_TICKET_ID,
ComponentVerifyTicket.class);
ComponentToken componentToken = getComponentToken(componentVerifyTicket.getComponentVerifyTicket());
String encryptAppId = ThirdPlat.PLAT_APPID;
String se_appId = EnDecryptUtil.d3esDecode(encryptAppId);
String requestUrl = AuthAccessUrl.API_QUERY_AUTHAPI.replace("COMPONENT_ACCESS_TOKEN", componentToken.getComponentAccessToken());
Map<String, String> map = new HashMap<String, String>();
map.put("component_appid", se_appId);
map.put("authorization_code", code);
String outputStr = JSONObject.toJSONString(map);
JSONObject jsonObject = HttpRequestUtils.httpRequest(requestUrl, "POST", outputStr);
AuthorizationInfo authorizationInfo = null;
if (jsonObject != null && jsonObject.getJSONObject("authorization_info") != null) {
long sys_time = System.currentTimeMillis();
authorizationInfo = jsonObject.getJSONObject("authorization_info").toJavaObject(AuthorizationInfo.class);
long expires = sys_time + 6600000;
authorizationInfo.setExpires_in(expires);
RedisService<AuthorizationInfo> redisService2 = RedisService.load();
redisService2.save(authorizationInfo, AuthorizationInfo.class);
}
return authorizationInfo;
}
【获取授权帐号调用令牌】:公众号/小程序的接口调用令牌authorizer_access_token 有效期为 2 小时,authorizer_access_token 失效时,可以使用 authorizer_refresh_token 获取新的 authorizer_access_token。
private static AuthorizationInfo refreshAuthorizerToken(AuthorizationInfo authorizationInfo) {
RedisService<ComponentVerifyTicket> redisService = RedisService.load();
ComponentVerifyTicket componentVerifyTicket = redisService.load(ComponentVerifyTicket.COMPONENT_VERIFY_TICKET_ID,
ComponentVerifyTicket.class);
ComponentToken componentToken = getComponentToken(componentVerifyTicket.getComponentVerifyTicket());
String encryptAppId = ThirdPlat.PLAT_APPID;
String se_appId = EnDecryptUtil.d3esDecode(encryptAppId);
String requestUrl = AuthAccessUrl.API_AUTHORIZER_TOKEN.replace("COMPONENT_ACCESS_TOKEN", componentToken.getComponentAccessToken());
Map<String, String> map = new HashMap<>();
map.put("component_appid", se_appId);
map.put("authorizer_appid", authorizationInfo.getAuthorizer_appid());
map.put("authorizer_refresh_token", authorizationInfo.getAuthorizer_refresh_token());
String outputStr = JSONObject.toJSONString(map);
JSONObject jsonObject = HttpRequestUtils.httpRequest(requestUrl, "POST", outputStr);
if(jsonObject != null) {
authorizationInfo.setAuthorizer_access_token(jsonObject.getString("authorizer_access_token"));
authorizationInfo.setAuthorizer_refresh_token(jsonObject.getString("authorizer_refresh_token"));
authorizationInfo.setExpires_in(System.currentTimeMillis() + 6600000);
RedisService<AuthorizationInfo> redisService2 = RedisService.load();
redisService2.save(authorizationInfo, AuthorizationInfo.class);
}
return authorizationInfo;
}
大概的入手开发顺序就是这样,只要能拿到component_access_token和authorizer_access_token,那就事半功倍了。至于写代码,当然,那又是一件大工程的事,想到这,头顶又秃了一大片。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海
- 点赞
- 收藏
- 关注作者
评论(0)