微信公众号和企业号接收消息和事件时用于加解密的类,即官方的WXBizMsgCrypt
类。(NodeJS版本)
$ npm install wxcrypt
import * as WXBizMsgCrypt from 'wxcrypt';
import WXBizMsgCrypt = require('wxcrypt');
const WXBizMsgCrypt = require('wxcrypt');
/**
* @param {string} token 公众号或企业微信Token
* @param {string} encodingAESKey 用于消息体的加密
* @param {string} appid 公众号的AppID或企业微信的CropID
*/
new WXBizMsgCrypt(token, encodingAESKey, appid);
注意:本方法仅企业微信可用
本函数实现:
- 签名校验
- 解密数据包,得到明文消息内容
/**
* 验证URL函数(仅用于企业微信)
* @param {string} msgSignature 从接收消息的URL中获取的msg_signature参数
* @param {string} timestamp 从接收消息的URL中获取的timestamp参数
* @param {string} nonce 从接收消息的URL中获取的nonce参数
* @param {string} echostr 从接收消息的URL中获取的echostr参数。注意,此参数必须是urldecode后的值
* @return {string} 解密后的明文消息内容,用于回包。注意,必须原样返回,不要做加引号或其它处理
*/
verifyURL(msgSignature, timestamp, nonce, echostr)
本函数实现:
- 签名校验
- 解密数据包,得到明文消息结构体
/**
* @param {string} msgSignature 从接收消息的URL中获取的msg_signature参数
* @param {string} timestamp 从接收消息的URL中获取的timestamp参数
* @param {string} nonce 从接收消息的URL中获取的nonce参数
* @param {string} postData 从接收消息的URL中获取的整个post数据
* @return {string} 解密后的msg,以xml组织
*/
decryptMsg(msgSignature, timestamp, nonce, postData)
本函数实现:
- 加密明文消息结构体
- 生成签名
- 构造被动响应包
/**
* 加密函数
* @param {string} replyMsg 返回的消息体原文
* @param {string} timestamp 时间戳,调用方生成
* @param {string} nonce 随机字符串,调用方生成
* @return {string} 用于返回的密文,以xml组织
*/
encryptMsg(replyMsg, timestamp, nonce)
调用方法时,如有错误,则会在错误对象上加上两个属性:
errcode
数字类型的错误码errmsg
错误描述
目前支持的错误码如下:
错误码 | 错误描述 |
---|---|
-40001 | 签名验证错误 |
-40002 | xml解析失败 |
-40003 | sha加密生成签名失败 |
-40004 | AESKey 非法 |
-40005 | appid/corpid 校验错误 |
-40006 | AES 加密失败 |
-40007 | AES 解密失败 |
-400011 | 生成xml失败 |
相关链接:
- 微信公众平台技术文档《消息加解密接入指引》
- 企业微信开发文档《加解密方案说明》
除了对WXBizMsgCrypt的实现,本项目还提供几个辅助函数。
传入若干个字符串,用于生成签名。可用于公众号url签名校验。具体算法为:
sha1(sort(str1、str2、...))
import { sign } from 'wxcrypt'; // ES6
const { sign } = require('wxcrypt'); // CommonJS
sign(...args: string[]): string;
传入任意对象,生成xml字符串。
注意:
- 支持的基本类型有
string
和number
,非法类型和null
会被转成空字符串- 最外层可以是对象、数组或基本类型
- 数组项会用
<item>
标签包起来
import { o2x } from 'wxcrypt'; // ES6
const { o2x } = require('wxcrypt'); // CommonJS
o2x(obj: any): string
数组项将用<item>
标签包裹,并成为兄弟节点
o2x({
xml: {
timestamp: 1536123965810,
articles: [
{
title: 'Article1',
desc: 'Description1'
},
{
title: 'Article2',
desc: 'Description2'
}
]
}
})
将返回如下字符串(格式化之后):
<xml>
<timestamp>1536123965810</timestamp>
<articles>
<item>
<title>Article1</title>
<desc>Description1</desc>
</item>
<item>
<title>Article2</title>
<desc>Description2</desc>
</item>
</articles>
</xml>
函数自动判断特殊字符的处理方式(使用CDATA或转义),具体如下:
- 含有特殊字符(
<>&'"
)时,使用CDATA处理 - 含有
]]>
时,由于会和CDATA冲突,使用转义处理
o2x({
xml: {
// 没有特殊字符,不处理
type: 'video',
// 引号是特殊字符,使用CDATA处理
title: '"愤怒"的小鸟',
// 含有"]]>",需要转义
description: ']]><[['
}
})
将返回如下字符串(格式化之后):
<xml>
<type>video</type>
<title><![CDATA["愤怒"的小鸟]]></title>
<description>]]><[[</description>
</xml>
传入xml字符串,生成js对象
注意:
- 虽然xml最外层应该只有一个根节点,但这不是强制的
- 除了
<item>
标签,兄弟节点的标签名不可以相同<item>
标签代表数组项,不可以与其他标签成为兄弟节点- 所有的文本节点都会转化为字符串(而不是数字或布尔类型)
import { x2o } from 'wxcrypt'; // ES6
const { x2o } = require('wxcrypt'); // CommonJS
x2o(xml: string): any
每个<item>
标签节点将转成一个数组项,且支持嵌套
x2o(`<xml>
<timestamp>1536123965810</timestamp>
<articles>
<item>
<title>Article1</title>
<desc>Description1</desc>
</item>
<item>
<title>Article2</title>
<desc>Description2</desc>
</item>
</articles>
</xml>`)
将返回如下对象:
{
xml: {
timestamp: '1536123965810',
articles: [{
title: 'Article1',
desc: 'Description1'
}, {
title: 'Article2',
desc: 'Description2'
}]
}
}