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

About

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

100.00 KiB
1 forks1 stars1 branches0 TagREADMEApache-2.0 license
Language
Go98.4%
Dockerfile1.6%