logo
1
1
WeChat Login

微信公众号草稿上传网关

一个简单的 HTTP 网关,用于上传微信公众号文章草稿。解决家庭网络出口 IP 动态变化导致无法通过微信 IP 白名单校验的问题。

功能特性

  • 上传图片素材到微信
  • 创建图文草稿
  • 创建图片消息(贴图)草稿
  • 支持多种上传方式:文件上传、URL、Base64
  • 多账号支持:可配置和管理多个微信公众号
  • 强制 API Key 认证:所有接口都需要认证
  • 请求频率限制:防止暴力破解(60次/分钟/IP)
  • 安全日志记录:记录所有请求用于审计

安全特性

  • 强制认证:必须配置 API Key(至少 16 字符),所有接口都需要认证
  • 常量时间比较:防止时序攻击
  • 频率限制:每个 IP 每分钟最多 60 次请求
  • 请求日志:记录客户端 IP、请求路径、认证失败等信息

快速开始

1. 编译

go build -o wechat-gateway ./main.go

2. 配置

生成安全的 API Key

# 使用 openssl 生成 32 字节的随机密钥 openssl rand -hex 32

单账号配置(简单模式)

创建配置文件 ~/.wechat-gateway.yaml

wechat: appid: "你的AppID" secret: "你的AppSecret" server: addr: ":8080" api_key: "你生成的安全密钥至少16字符" # 必填

或使用环境变量:

export WECHAT_APPID=你的AppID export WECHAT_SECRET=你的AppSecret export API_KEY=你生成的安全密钥至少16字符

多账号配置

accounts: personal: name: "个人公众号" appid: "wx1234567890abcdef" secret: "secret1" company: name: "公司公众号" appid: "wx0987654321fedcba" secret: "secret2" default_account: "personal" server: addr: ":8080" api_key: "你生成的安全密钥至少16字符" # 必填

3. 运行

./wechat-gateway # 或指定监听地址 ./wechat-gateway -addr :9000

4. Docker 运行

方式一:本地构建镜像

docker build -t wechat-article-pushgateway:local .

方式二:使用 GitHub Actions 自动构建的镜像

推送到 main/masterv* tag 后,GitHub Actions 会自动发布镜像到:

docker.cnb.cool/znb/wechat-pushgateway

拉取方式:

docker pull docker.cnb.cool/znb/wechat-pushgateway

使用配置文件运行

推荐把配置文件挂载到容器内的 /app/config.yaml

docker run -d \ --name wechat-article-pushgateway \ --restart always \ -p 8080:8080 \ -v $(pwd)/config.yaml:/app/config.yaml:ro \ docker.cnb.cool/znb/wechat-pushgateway

如果你使用本地构建的镜像,将镜像名替换为 wechat-article-pushgateway:local 即可。

使用环境变量运行

适合单账号场景:

docker run -d \ --name wechat-article-pushgateway \ --restart always \ -p 8080:8080 \ -e WECHAT_APPID=你的AppID \ -e WECHAT_SECRET=你的AppSecret \ -e API_KEY=你生成的安全密钥至少16字符 \ docker.cnb.cool/znb/wechat-pushgateway

使用 Docker Compose

services: wechat-article-pushgateway: image: docker.cnb.cool/znb/wechat-pushgateway container_name: wechat-article-pushgateway restart: always ports: - "8080:8080" volumes: - ./config.yaml:/app/config.yaml:ro

启动:

docker compose up -d

查看日志:

docker compose logs -f

默认工作目录是 /app,如果挂载 config.yaml/app/config.yaml,程序会自动读取。

Docker 部署建议

  • 服务器建议使用固定公网 IP,并将该 IP 加入微信公众号后台白名单
  • 建议在容器前面加一层 Nginx/Caddy,并通过 X-Forwarded-For 保留真实来源 IP
  • 建议只暴露给可信调用方,或在防火墙层限制来源 IP
  • 配置文件中请务必使用足够长的 api_key
  • 容器本身无状态,不依赖本地持久化数据,升级时只需替换镜像并保留配置文件

GitHub Actions

仓库新增了 GitHub Actions 工作流 docker.yml

  • 推送到 main/master 时自动构建并推送镜像
  • 推送 v* tag 时自动发布版本镜像
  • Pull Request 时只构建校验,不推送
  • 镜像默认发布到 ghcr.io/<owner>/<repo>

首次使用时,确认 GitHub 仓库允许 GITHUB_TOKEN 写入 Packages。

API 接口

指定账号

多账号模式下,可通过以下方式指定账号(按优先级排序):

  1. JSON body 字段"account": "company"
  2. URL 参数?account=company
  3. HTTP 请求头X-Account: company

未指定时使用默认账号。

获取账号列表

GET /api/accounts

响应:

{ "accounts": [ {"key": "personal", "name": "个人公众号", "appid": "wx12***cdef", "is_default": "true"}, {"key": "company", "name": "公司公众号", "appid": "wx09***dcba", "is_default": "false"} ], "default_account": "personal" }

健康检查

GET /health

上传素材

# 文件上传 POST /api/material/upload Content-Type: multipart/form-data file: <图片文件> # URL 上传 POST /api/material/upload Content-Type: application/json { "url": "https://example.com/image.jpg", "account": "company" } # Base64 上传 POST /api/material/upload Content-Type: application/json { "base64": "data:image/jpeg;base64,...", "filename": "image.jpg", "account": "personal" }

响应:

{ "media_id": "xxx", "wechat_url": "https://...", "account": "company" }

创建图文草稿

POST /api/draft/create Content-Type: application/json { "account": "personal", "articles": [ { "title": "文章标题", "content": "<p>HTML 内容</p>", "thumb_media_id": "xxx", "author": "作者", "digest": "摘要", "show_cover_pic": 1 } ] }

响应:

{ "media_id": "xxx", "account": "personal" }

创建图片消息草稿

POST /api/draft/newspic Content-Type: application/json { "account": "company", "articles": [ { "title": "标题", "content": "纯文本描述", "image_media_ids": ["media_id_1", "media_id_2"] } ] }

获取 Access Token(调试用)

GET /api/token?account=personal

认证

API Key 认证是强制的。所有请求必须包含认证头:

curl -H "Authorization: Bearer 你的api_key" http://localhost:8080/api/material/upload # 或 curl -H "X-API-Key: 你的api_key" http://localhost:8080/api/material/upload

未认证或认证失败的请求将返回 401 错误。

部署

将此网关部署到有固定 IP 的服务器上,然后将该 IP 添加到微信公众号的 IP 白名单中。

使用 systemd(Linux)

[Unit] Description=WeChat Draft Upload Gateway After=network.target [Service] Type=simple User=www-data ExecStart=/path/to/wechat-gateway Restart=always Environment=WECHAT_APPID=your_appid Environment=WECHAT_SECRET=your_secret [Install] WantedBy=multi-user.target

使用 Docker

推荐直接使用上面的 Docker 运行方式,不需要再手写 Dockerfile。

最常见的生产部署命令:

docker run -d \ --name wechat-article-pushgateway \ --restart always \ -p 8080:8080 \ -v /opt/wechat-gateway/config.yaml:/app/config.yaml:ro \ docker.cnb.cool/znb/wechat-pushgateway

更新镜像:

docker pull docker.cnb.cool/znb/wechat-pushgateway docker rm -f wechat-article-pushgateway docker run -d \ --name wechat-article-pushgateway \ --restart always \ -p 8080:8080 \ -v /opt/wechat-gateway/config.yaml:/app/config.yaml:ro \ docker.cnb.cool/znb/wechat-pushgateway