一、接着上文
上文把部署情况介绍了,侧重于网络及代理,本文选择把微信公众号的对接实现介绍一下。
还是那句话,微信官方的文档已非常详细,这里先摘抄一些重要的概念。
其次,待对接微信公众号的接口众多,我们只为获取openId,只需要对接那么几个接口。
二、术语
1、用户
支付请求必须有appId和openId,所谓微信公众号的对接,对于我来说,就是为获取微信用户的openId。
为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID。
2、什么是accessToken
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取access_token失效。
3、公众号的appId和appSecret
在所有的接口中,都必须传入这两个字段。所以你得找到它们。
4、安全文件
公众号设置->功能设置, 依次设置业务域名、JS接口安全域名和网页授权域名。
将文件MP_verify_sJ7aG7qAZXmLo2xl.txt(点击下载)上传至填写域名或路径指向的web服务器(或虚拟主机)的目录(若填写域名,将文件放置在域名根目录下,例如wx.qq.com/MP_verify_sJ7aG7qAZXmLo2xl.txt;若填写路径,将文件放置在路径目录下,例如wx.qq.com/mp/MP_verify_sJ7aG7qAZXmLo2xl.txt),并确保可以访问。
我这里把上面文件已保存至192.168.2.70所在的前端h5服务器。
三、对接实现
开源的微信公众号对接实现:WxJava ,及其对接示例:weixin-java-mp-demo。对接的接口比较全面,我们只选择了几个需要对接的接口。
1、对接流程
2、获取授权码和网页授权access_token
参考微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
写得真的是太详细了,有接口有入参还有示例。(真的是有点太白看到崔颢写的登黄鹤楼有得一比)
如果你获取accessToken报错40164错误码,提示你的Ip非法,那么有两种可能:一是你没有把外网出口IP添加到白名单;二是刚添加白名单,需要等几分钟后才生效。
- 获取授权码code:https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
- 通过code获取网页授权access_token:https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code
返回字段说明截图,见下:
3、获取access_token
获取access_token的接口是:https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential
参考微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
注意:这里有两个access_token,别混淆错了。
至此,我们简易的对接微信公众号的接口就已满足了。(你有可能还需要定期刷新access_token、获取ticket并管理、根据openId查询用户信息等)
/**
* 获取微信预授权code
*/
private String authCode = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
/**
* 根据微信授权码code获取网页授权access_token和openId
*/
private String pageAuthAccessToken = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
/**
* 获取access_token
* 和下面的接口有所区别:本接口是生成access_token,而下面的接口生成的是网页授权access_token。
*/
private String accessToken = "https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential";
/**
* 刷新access_token
*/
private String refreshAccessToken = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";
/**
* 获取ticket
*/
private String jsApiTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
/**
* 获取用户基本信息
*/
private String userInfo = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
4、多个公众号的配置
简单设计思路:
使用一个Map存储,key是appCode,value信息包括appId、appSecret等。
这里摘抄开源项目的代码:
- yml配置文件
wx:
mp:
configs:
- appId: wxs9a9692ecfa0kdbc # 第一个公众号的appid
secret: 83623c6ab0f33f54266old04df7x02sa # 公众号的appsecret
token: # 接口配置里的Token值
aesKey: # 接口配置里的EncodingAESKey值
- appId: # 第二个公众号的appid,以下同上
secret:
token:
aesKey:
- java源码
package com.github.binarywang.demo.wx.mp.config;
import com.github.binarywang.demo.wx.mp.utils.JsonUtils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* wechat mp properties
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpProperties {
/**
* 多个公众号配置信息
*/
private List<MpConfig> configs;
@Data
public static class MpConfig {
/**
* 设置微信公众号的appid
*/
private String appId;
/**
* 设置微信公众号的app secret
*/
private String secret;
/**
* 设置微信公众号的token
*/
private String token;
/**
* 设置微信公众号的EncodingAESKey
*/
private String aesKey;
}
@Override
public String toString() {
return JsonUtils.toJson(this);
}
}
5、权限校验
在获取微信授权码code后,调用登录接口,生成并颁发token给客户端。
后面的接口都需要校验,以保护后端的业务接口安全。
简要的校验实现:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(filterName = "jwtFilter", urlPatterns = {"/api/*"})
public class JwtFilter implements Filter {
private static String PREFIX = "Bearer ";
private static String AUTHORIZATION = "AUTHORIZATION";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest r = (HttpServletRequest) request;
String path = r.getRequestURI();
# 登录接口排除在外
if (path.contains("api/v1/login")) {
chain.doFilter(request, response);
} else {
String token = r.getHeader(AUTHORIZATION);
# 校验token的合法
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
四、总结
回到我们的目标,本文非对接全部的微信公众号,只需两个接口。
正所谓“弱水三千,只取一瓢饮”,还是那句话,你如果要对接其他的更多接口,请参考上文给的开源项目。
有了用户公众号的openId,后面的支付接口测试就能进展下去了。
至于具体的支付联调,待后面有时间再补充。