0%

midway 微信公众号(一) 接入公众号开发设置

闲来无事,忽然想起以前的公众号还是在玩php的时候接入了一下,现在废弃好久了,正好使用midway构造了一个api,来尝试将api和公众号结合起来,练练手。

公众号后台接入设置

首先在公众号后太进行基本的开发配置,开发 -> 基本配置 -> 填写服务器配置,如下图所示,填入对应的URL(api的地址)、Token(算是一个自己的秘钥吧),消息加密方式就选择土建的安全模式即可。

公众号后台开发设置

现在我们点击提交会告诉我们接入失败的,因为我们还没有写相关服务器的接入代码。

接入流程

首先我们看微信公众号官方文档是怎么写的,文档地址:接入指南。可以看到,当我们在公众号后台配置好开发服务器信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数为:

  • signature 微信加密签名,结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
  • timestamp 时间戳
  • nonce 随机数
  • echostr 随机字符串

校验信息:

  1. tokentimestampnonce三个参数组合为数组,然后进行字典排序。
  2. 将第一步得到的数组组合为字符串,然后进行sha1加密。
  3. 将加密后的字符串与signature相比,如果相同就说明验证通过。
  4. echostr字符串返回。

midway 代码相关

首先我们需要构造一个路由,这个路由需要直接通过域名访问到,类似于:http://baidu.com这样访问到的路由。

1
2
3
4
@get('/')
async index(ctx: IApplicationLocals) {
// pass
}

设置配置参数

公众号里面会有很多秘钥之类的参数,我们为了统一管理,在配置文件config.defualt.ts中开一个配置项来管理这些参数。目前我们用到的只有token,所以可以如下配置:

1
2
3
4
// 公众号配置
config.mpWeixin = {
token: 'xxx',
};

interface.ts中定义这个配置的interface

1
2
3
export interface IMpWeixin {
token: string;
}

接收参数,构造数组并字典排序

我们需要从请求中获得的参数有:signaturenonceechostrtimestamptoken我们已经配置在config.default.ts中了,直接获取即可。所以我们的代码:

1
2
3
4
5
6
7
8
@config('mpWeixin')
mpWexin: IMpWeixin;

@get('/')
async index(ctx: IApplicationLocals) {
const {signature, timestamp, nonce, echostr} = ctx.query;
const str = [this.mpWexin.token, timestamp, nonce].sort().join('');
}

Array.prototype.sort()方法返回的结果就是字典排序后的数组。

sha1 加密

SHA(安全散列算法,Secure Hash Algorithm)是一种数据加密算法。该算法的思想是接收一段明文,并把它转化为长度较短、位数固定的输出序列即散列值的过程。散列函数值可以说是对明文的一种“指纹”或是“摘要”,所以对散列值的数字签名就可以视为对此明文的数字签名。sha1适用于长度不超过2^64二进制位的消息。

我们可以引入node的crypto模块来做sha1加密。

引入crypto模块的createHash

1
import {createHash} from 'crypto';

定义一个加密方法:

1
2
3
4
5
encrypt(algorithm, content) {
const hash = createHash(algorithm);
hash.update(content);
return hash.digest('hex');
}

使用:

1
const tempStr = this.encrypt('sha1', str);

将加密后的字符串和signature对比,如果相等就返回echostr

1
2
3
4
5
if (tempStr === signature) {
ctx.body = echostr;
} else {
ctx.body = 'error';
}

完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { controller, config, get, provide,  IApplicationLocals } from 'midway';
import {createHash} from 'crypto';
import {IMpWeixin} from "../../interface";
@provide()
@controller('/')
export class HomeController {

@config('mpWeixin')
mpWexin: IMpWeixin;

@get('/')
async index(ctx: IApplicationLocals) {
const {signature, timestamp, nonce, echostr} = ctx.query;
const str = [this.mpWexin.token, timestamp, nonce].sort().join('');
const tempStr = this.encrypt('sha1', str);
if (tempStr === signature) {
ctx.body = echostr;
} else {
ctx.body = 'error';
}
}

encrypt(algorithm, content) {
const hash = createHash(algorithm);
hash.update(content);
return hash.digest('hex');
}
}

上传服务器并验证

将代码上传到服务器,并重新启动。

然后返回到微信公众号后台,继续点击提交,即可看到验证成功。接入成功。


完成了公众号和api的对接,后续可以继续实现一些想法。