微信公众号开发系列(1)-公众号服务器认证

概述
微信作为中国目前使用人数最多的实时通讯工具和微生态平台,自己却一直没有这方面的开发经验,想想确实挺遗憾的。况且自己一直自认为是一个还不错的后端工程师,这方面的短板是一直想补齐一下的。最近正好有时间,有精力,打算好好学习下这块。

首先,需要准备如下:

  1. 公众号(个人练习的话可以用微信测试平台,下面有链接)

  2. 云主机。用来做公众号服务器

公众号

微信公众号分为订阅号和服务号,又分别分为认证和非认证。拥有的接口权限如下图:

微信公众号开发系列(1)-公众号服务器认证_第1张图片
image

总体来说权限规律为服务号>订阅号,认证的 >非认证的。个人非认证订阅号是最容易申请的,认证的话需要提交公司的认证。服务号申请更复杂一些。如果只是个人练习的话建议用微信测试平台(http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login )练习。笔者想顺便写点东西,所以搞了个个人订阅号。

云主机

首先说下为什么需要云主机呢?

开发微信公众号本质上和通常的网站开发并无区别。当我们进入一个公众号页面之后,我们可以向公众号发送文字、语音、图片等消息,也可以通过点击页面下方的菜单触发相应的功能。那么开发者与微信用户究竟是怎么进行交互的呢?实际上我们在公众号里的所有操作,都会发送到微信的服务器上,微信服务器将这些动作的具体含义按照一定的格式进行封装后,发送到微信公众号所对应的服务器上(这个服务器的地址可以由开发者在微信公众号的后台进行配置),开发者通过编写代码来处理不同的用户行为,并将处理后的结果按照一定的格式返回给微信服务器,再由微信服务器发送到微信公众号里面,从而完成了一次交互过程。在这里借用方倍老师博客中的一张图片来展示下这个过程,可以帮助大家理解地更清楚:

微信公众号开发系列(1)-公众号服务器认证_第2张图片
image

微信服务器和我们的公众号服务器通讯有个前提:两者需要彼此认证。这也是本文要讲的重点。

首先要在公众号开发选项下面的基本配置里配置公众号开发信息和服务器配置信息。

微信公众号开发系列(1)-公众号服务器认证_第3张图片
image

然后我们需要实现认证接口的代码,笔者对java比较熟悉。所以这里用Java演示。官方文档参考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

接口代码如下:

@RestController
@RequestMapping("/auth/")
public class AuthController {

    private static final Logger LOGGER =LoggerFactory.getLogger(AuthController.class);

    @GetMapping("/handshake")
    public String handShakeAuth(
            @RequestParam(name = "signature") String signature,
            @RequestParam(name = "timestamp") String timestamp,
            @RequestParam(name = "nonce") String nonce,
            @RequestParam(name = "echostr") String echostr
    ) {
        LOGGER.info("signature:{},timestamp:{},nonce:{},echostr:{}",signature,timestamp,nonce,echostr);
        if(SignUtil.checkSignature(signature,timestamp,nonce)){
            return echostr;
        }
        throw new RuntimeException("非法请求");
    }
}

认证逻辑如下:

package com.jack.wechat.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
 * @author: jacky
 * @date: 2019/3/14
 */
public class SignUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(SignUtil.class);
    // 与接口配置信息中的 Token 要一致
    private static final String token = "jacky";

    /**
     * 验证签名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[]{token, timestamp, nonce};
        // 将 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");
            // 将三个参数字符串拼接成一个字符串进行 sha1 加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            LOGGER.error("Error msg:{}", e.getMessage());
        }

        content = null;
        // 将 sha1 加密后的字符串可与 signature 对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     *
     * @param mByte
     * @return
     */
    private 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;
    }
}

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

1)将token、timestamp、nonce三个参数进行字典序排序 2)将三个参数字符串拼接成一个字符串进行sha1加密 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。

如果你是http协议的接口,端口号要记得设置为80。

最后在云主机上搭建个web服务就好了。正常的话会提示你认证成功。否则检查下配置信息是否按微信要求的做了。比如:端口号,token等。

第一篇比较基础,后面会慢慢探索更多的功能开发。

你可能感兴趣的:(微信公众号开发系列(1)-公众号服务器认证)