开发接入2.1微信公众平台接口测试账号的申请流程及步骤

优采云 发布时间: 2021-08-01 00:31

  开发接入2.1微信公众平台接口测试账号的申请流程及步骤

  一、前言

  随着微信的普及,年轻一代逐渐从QQ转向微信。界面简洁,功能强大,男女老少皆宜,是微信的特色。正是这一特性,使微信成为了中国社交软件的巨头。因此,很多产品需要在微信中开发以满足需求。

  本文主要讲服务号的开发,与微信服务器的交互,以及使用微信公众号的Oauth2授权,在微信中展示本地开发的内容并进行交互。由于公众号申请需要时间和经验,需要公司相关资质,作为个人开发者,可以先在微信官方平台申请测试号,使用测试号授权与微信服务器交互并调试这一页。在开始之前,朋友们需要了解他们的需求。微信分为企业号、服务号、订阅号。不同的账户有不同的功能。具体可以到微信官网查看需要开发什么类型的账号。

  

  二、development 接入2.1 微信公众平台接口测试账号申请

  如前言所述,在开发中,我们一半人会使用官方微信公众号作为我们的生产线环境,然后aut环境可以使用测试号进行开发,从而实现与微信的交互。测试账号申请链接如下

  测试帐户申请

  进入后,您将看到以下屏幕。登录

  

  登录后,您会看到以下屏幕:

  

  因为我已经配置好了,所以显示配置后的相关参数。如果是第一次进入,需要自己配置相关参数。首先要注意的是,系统会为你生成一个appId,appsercet,后面会讲到这个的作用。现在你需要配置 URL 和 Token。

  具体来说,这个所谓的URL就是你需要在你的代码中与微信进行Token验证交互的一种方法。配置完成后,微信会使用配置的url发起http请求。请注意,发起方法是获取请求。因此,代码中提供的接口需要将请求头设置为get请求:

  method=(RequestMethod.GET) 方法中需要验证微信发送的消息。下面的token需要和你项目中配置的token一致。微信发送请求后,会带上签名和时间戳。 , 随机数被检查。如果匹配成功,则可以进行下一步。如果不一致,则匹配失败。需要注意的是,这个url需要有自己的域名。我个人在Sunny-Ngrok上申请了内网穿透,并赠送了一个域名。

  2.2 sunn-Ngrok 内网渗透账号申请

  点击申请账号

  

  账户创建后,会有如上图所示。其实,开通域名的方式有很多种。这里我只是给我一个参考方法。然后点击打开隧道,购买隧道

  

  一个月10元不算贵。购买后点击隧道管理

  

  购买后会有记录,可以同时查看赠送域名和查看状态。此时的状态为离线。如果是离线,微信公众平台微信发起的请求无法配置从本机接受,需要到官网下载客户端启动隧道。

  cmd命令行进入sunny.exe所在目录并执行

  sunny.exe clientid 隧道 ID

  

  如上图所示,将域名指向你本地的ip和端口号后,就可以在公众号提交配置了。在我自己机器的代码中,我做了如下配置:

  @RequestMapping(value = "/wx/wxmsgreceive", method = {RequestMethod.GET})

public void verifywxtoken(HttpServletRequest request, HttpServletResponse response) throws Exception {

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

logger.info("开始校验信息是否是从微信服务器发出");

// 签名

String signature = request.getParameter("signature");

// 时间戳

String timestamp = request.getParameter("timestamp");

// 随机数

String nonce = request.getParameter("nonce");

// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败

String result = Sha1.gen(SERVER_TOKEN, timestamp, nonce);

if (signature.equals(result)) {

// 随机字符串

String echostr = request.getParameter("echostr");

logger.debug("接入成功,echostr {}", echostr);

response.getWriter().write(echostr);

}

}

  微信验证码

  public static String gen(String token, String timestamp, String nonce) throws NoSuchAlgorithmException {

String[] arr = new String[]{token, timestamp, nonce};

Arrays.sort(arr);

StringBuffer content = new StringBuffer();

for (String a : arr) {

content.append(a);

}

return DigestUtils.sha1Hex(content.toString());

}

  因为我配置的请求头是/wx/wxmsgreceive,所以公共平台上的配置页面是域名+/wx/wxmsgreceive。

  此时,当您在网页上点击提交时,微信会向本机发送认证请求,以确保本机的服务必须开启。

  

  这是官方的说明,所以我们开发的项目中需要提供一个暴露的接口来验证微信服务器,主要是验证微信公众号网页上填写的token验证。官方文档说明如下:

  

  所以在项目中,放置在配置文件或常量池中的token必须是微信公众号访问中填写的token的字符串。如果输入不同或者方法中的解密比较有问题,在网页上点击确定,就会出现“失败”字样。

  

  

  2.3 微信开发者工具准备

  下载微信开发者工具。

  点击下载微信开发者工具

  

  下载完成后扫码登录

  

  选择微信公众号网页开发

  

  

  此工具是后续开发中访问URL和前端调试必不可少的工具。

  2.3 Oauth2 授权

  此时测试号已经配置好了,那么接下来我们如何开发呢?在微信公众号页面,部分页面需要根据用户的身份回显不同的信息,比如用户的还款清单。这些实现首先需要获取个人信息然后与数据库进行交互,需要获取用户的唯一标识。在微信中,每个人都有并且只有一个唯一标识openId。这个openId需要通过微信的授权和回调获取。同时,微信公开文档上也有详细的授权方式介绍。如何授权可以根据自己的业务需要使用。在实际业务中,根据项目的特点固化不同的用户。我们所做的是将用户固化到数据库中,生成一个 UUID,并将 UUID 放入 cookie。授权非常重要。通过它的控件,我们可以通过获取当前用户的openid来比较用户是会员还是普通会员,是非管理员还是管理员等。这在页面跳转中起着至关重要的作用。同时,在代码中,一些静态页面可能不一定需要授权,任何人都可以查看。所以在代码中,我使用了一个过滤器,直接在前台发布了一系列.css、.js、.html等。特殊要求,我拉过来,要求微信授权。例如,我在项目中。 .go请求中需要验证,通过微信回调获取当前用户信息,固化用户。代码如下:

  @WebFilter(urlPatterns = "/*", filterName = "authFilter")

public class AuthFilter implements Filter {

private final Logger logger = LoggerFactory.getLogger(AuthFilter.class);

@Autowired

private GeneralConfigService gcService;

@Autowired

private WxUserVerify wxUserVerify;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;

try {

String url = request.getRequestURI();

logger.info("URL:" + url);

// 1.请求内容为WEB静态内容时直接放行

if (StringUtil.separatorEndWith(gcService.getStaticResourceConfig(), url)) {

chain.doFilter(servletRequest, servletResponse);

return;

}

// 2.不是静态资源进行验证

if(!checkUrl(request, response, url)){

return;

}

chain.doFilter(servletRequest, servletResponse);

return;

} catch (FilterException e1) {

//自定义异常,这里可以直接把错误信息抛出去,不需要记录日志,因为这里是业务异常。

ResponseUtil.error(response, e1.getMessage());

} catch (Exception e2) {

//无法捕捉的异常,不能直接把错误信息抛出去,需要包装下错误信息

logger.error(e2.getMessage(), e2);

ResponseUtil.error(response, "系统异常,请稍后再试...");

}

}

/**

* 与数据库配置url进行匹配

* @param request

* @param response

* @param url

* @return

*/

private boolean checkUrl(HttpServletRequest request, HttpServletResponse response, String url) {

boolean passFlag=true;

//与数据库进行匹配

Map urlConfig = getUrlConfig();

//比较匹配项

String substring = url.substring(url.lastIndexOf("/") + 1);

if (!urlConfig.containsKey(substring)) {

return passFlag;

}

CallBackMsg msg = wxUserVerify.doVerify(request, response);

if (msg.getResultCode().equals(CallBackMsg.WX_VALID_CONTINUE)) {

passFlag=false;

} else if (msg.getResultCode().equals(Const.ERROR_CODE)) {

throw new FilterException(FilterExceptionEnum.ERROR_WX_VALID_FAILE);

}

return passFlag;

}

/**

* 获取地址配置信息

* @return

*/

private Map getUrlConfig() {

// 3.获取需要验证用户的请求配置

Map configAddressList = gcService.getConfigAddressList();

logger.info(configAddressList.toString());

if (configAddressList.isEmpty()) {

logger.error("urlValidConfig为空,请检查!");

throw new FilterException(FilterExceptionEnum.ERROR_VALIDCONF_NULL);

}

return configAddressList;

}

@Override

public void destroy() {

}

}

  通过创建一个类来实现Filter过滤器进行验证,@WebFilter(urlPatterns = "/*", filterName = "authFilter")对所有请求进行过滤拦截,其中封装的方法当是特定请求时会被拉取申请授权

  private CallBackMsg impower(HttpServletRequest request, HttpServletResponse response) {

CallBackMsg msg = new CallBackMsg();

String code = request.getParameter("code");

try {

// 从配置获取access_token

String appId = getWxParams("wxAppid");

String secret = getWxParams("wxSecret");

String accessTokenUrl = gcService.getUrlWxFwGetToken() + "?appid=" + appId + "&secret=" + secret + "&code="

+ code + "&grant_type=authorization_code";

logger.info("accessTokenUrl:" + accessTokenUrl);

String accessTokenResult = "";

if (StringUtil.isEmpty(proxyFlag)) {

proxyFlag = gcService.getProxyFlag();

}

if (Const.PROXY_FLAG_USED.equals(proxyFlag)) {

accessTokenResult = HttpUtils.sendPostHttpsViaProxy(accessTokenUrl, "", gcService.getProxyIp(),

gcService.getProxyPort());

} else {

accessTokenResult = HttpUtils.sendPostHttps(accessTokenUrl, "");

}

logger.info("accessTokenResult:" + accessTokenResult);

JSONObject accessTokenJson = JSONObject.parseObject(accessTokenResult);

String accessToken = accessTokenJson.getString("access_token");

logger.info("accessToken:" + accessToken);

String openid = accessTokenJson.getString("openid");

logger.info("openid:" + openid);

// 查询数据库中的用户数据

String reqUrl = gcService.getSkylarkServiceUrl() + "wechat/searchwxuserinfo";

ResponseDto responseQuery = this.restInvoke(reqUrl, getQueryParam(openid, null, 1));

String userInfoDb = responseQuery.getRspMesg();

JSONObject userInfoDbJson = JSONObject.parseObject(userInfoDb);

String uuid = "";

// 数据库不存在该用户则保存数据库,存在则返回已存在的UUID

if (StringUtils.isEmpty(userInfoDbJson)) {

// 查询微信中的用户数据

uuid = UUIDGenerator.genUUID();

// 获取用户信息

String userInfoUrl = gcService.getUrlWxFwGetUser() + "?access_token=" + accessToken + "&openid="

+ openid + "&lang=zh_CN";

logger.info("userInfoUrl:" + userInfoUrl);

String userInfoResult = "";

if (Const.PROXY_FLAG_USED.equals(proxyFlag)) {

userInfoResult = HttpUtils.sendPostHttpsViaProxy(userInfoUrl, "", gcService.getProxyIp(),

gcService.getProxyPort());

} else {

userInfoResult = HttpUtils.sendPostHttps(userInfoUrl, "");

}

logger.info("userInfoResult:" + userInfoResult);

JSONObject userInfoJson = JSONObject.parseObject(userInfoResult);

// 固化用户

String addReq = gcService.getSkylarkServiceUrl() + "wechat/addwxuserinfo";

ResponseDto addResp = this.restInvoke(addReq,

getEntityParam(uuid, openid, userInfoJson));

// 失败另处理

if (!(Const.SUCCESS_CODE).equals(addResp.getRspCode())) {

// 保存数据失败,认证失败

msg.setResultCode(Const.ERROR_CODE);

return msg;

}

} else {

uuid = userInfoDbJson.getString("id");

}

// 权限:本项目中的类都可以访问该cookie,存储到客户端

Cookie cookie = new Cookie(Const.TOKEN, uuid);

cookie.setPath("/");

response.addCookie(cookie);

//将token存入session

HttpSession session = request.getSession();

session.setAttribute("authToken",uuid);

} catch (IOException e) {

logger.error(e.getMessage());

}

msg.setResultCode(Const.SUCCESS_CODE);

return msg;

}

  因为项目中使用了代理服务器,不需要本地开发,所以方法有点乱,但是大体思路是客户端发起带有特殊后缀的请求时,被过滤器拦截接下来,与微信服务器进行交互授权的过程。授权成功后,向微信提供回调地址,并将微信带回的用户信息保存在表中。同时,当前用户在库表中生成的唯一标识标识存储在cookie域中。

  

  这样就可以将获取到的openid放入cookie中了。那么这个openId就可以固化了,也就是存储在数据库中。在会话中,如果点击某个页面需要使用微信授权,可以先从cookie域中获取。如果cookie不可用,则向微信发起授权请求,获取openid后,存储cookie和curing。有一些步骤可以实现这一点。微信开放平台上有相关的demo。如果您需要我提供它们,请留言。后续授权码我会贴出来供大家参考。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线