Files
wxauto_api/doc/wxautorelogin/README.md
T
2026-04-07 14:11:45 +08:00

14 KiB
Raw Blame History

WXAuto Relogin - 微信自动重登录方案

1. 背景问题

1.1 当前痛点

  • 微信掉线后,需要人工介入扫码登录
  • 节点多时,人工操作繁琐
  • 无法远程自动恢复微信会话

1.2 现有架构

中控(Center) ←→ 节点(Node)
                 ↑
           API通信/回调

2. 解决方案概述

2.1 核心理念

微信掉线 → 中控告警 → 客户端接收 → 获取二维码 → 回传中控 → 前端展示扫码

2.2 系统架构

┌─────────────────────────────────────────────────────────────┐
│                     WXAuto Center                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │  告警系统    │→ │  插件系统    │← │  前端展示    │   │
│  │  (Webhook)   │  │(wxautorelogin)│  │  (二维码)    │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
│         ↑                                     │           │
│         │         ┌──────────────┐           │           │
│         └─────────│  回调接口    │───────────┘           │
│                   │ /callback   │                       │
│                   └──────────────┘                       │
└─────────────────────────────────────────────────────────────┘
                            ↑ HTTP
┌─────────────────────────────────────────────────────────────┐
│                    WXAuto Relogin Client                    │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │  消息接收    │  │  二维码获取  │→ │  状态回调    │   │
│  │  (Webhook)   │  │(get QR code) │  │  (重置微信)  │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
└─────────────────────────────────────────────────────────────┘

3. 实现方案

3.1 中控端改动

3.1.1 新增 API 接口

接口 方法 说明
POST /api/v1/callback/relogin/qrcode 接收二维码 客户端回传二维码图片
GET /api/v1/nodes/{node_id}/relogin/status 重登录状态 查询节点重登录进度

3.1.2 二维码存储结构

# NodeReloginStatus
{
    "node_id": "wx1",
    "status": "waiting_qrcode" | "qrcode_ready" | "scanned" | "confirmed" | "completed" | "failed",
    "qrcode_base64": "data:image/png;base64,...",
    "qrcode_expires_at": "2026-04-07T15:30:00",
    "created_at": "2026-04-07T15:00:00",
    "updated_at": "2026-04-07T15:05:00"
}

3.1.3 前端展示

  • 节点详情页增加"重登录"标签页
  • 实时显示二维码(轮询 /api/v1/nodes/{node_id}/relogin/status
  • 二维码过期提示

3.2 客户端改动

3.2.1 Webhook 接收器

客户端需要暴露一个 HTTP 接口接收中控告警:

# client/webhook_server.py
from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.post("/webhook/relogin")
async def receive_alert(data: dict):
    """
    接收中控的掉线告警
    {
        "event": "wechat_offline",
        "node_id": "wx1",
        "node_name": "微信1",
        "wechat_status": "offline",
        "timestamp": "2026-04-07T15:00:00"
    }
    """
    # 触发获取二维码流程
    await trigger_relogin(node_id=data["node_id"])
    return {"status": "ok"}

async def trigger_relogin(node_id: str):
    # 1. 调用节点API获取二维码
    # 2. 上传二维码到中控
    # 3. 等待扫码确认
    pass

3.2.2 二维码获取流程

async def get_qrcode_from_node(api_url: str, api_key: str) -> bytes:
    """
    从wxauto节点获取二维码
    GET /api/wechat/qrcode
    返回: PNG图片二进制
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{api_url}/api/wechat/qrcode",
            headers={"X-API-Key": api_key}
        )
        return response.content

async def upload_qrcode_to_center(center_url: str, node_id: str, qrcode_bytes: bytes):
    """
    上传二维码到中控
    POST /api/v1/callback/relogin/qrcode
    """
    async with httpx.AsyncClient() as client:
        import base64
        qrcode_base64 = base64.b64encode(qrcode_bytes).decode()
        await client.post(
            f"{center_url}/api/v1/callback/relogin/qrcode",
            json={
                "node_id": node_id,
                "qrcode_base64": qrcode_base64
            }
        )

3.2.3 扫码状态轮询

async def wait_for_scan(center_url: str, node_id: str, timeout: int = 120):
    """
    轮询中控接口,等待用户扫码确认
    """
    start_time = time.time()
    while time.time() - start_time < timeout:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{center_url}/api/v1/nodes/{node_id}/relogin/status"
            )
            status = response.json()
            if status["status"] == "completed":
                return True
            elif status["status"] == "failed":
                return False
        await asyncio.sleep(2)
    return False

4. 完整流程时序

4.1 时序图

┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│  微信   │    │  节点   │    │  中控   │    │  客户端 │    │  用户   │
└────┬────┘    └────┬────┘    └────┬────┘    └────┬────┘    └────┬────┘
     │               │               │               │               │
     │  掉线         │               │               │               │
     │───────────────→│               │               │               │
     │               │  wechat_offline callback      │               │
     │               │───────────────→│               │               │
     │               │               │  Webhook告警   │               │
     │               │               │───────────────→│               │
     │               │               │               │               │
     │               │               │               │  获取二维码     │
     │               │  GET /qrcode │               │───────────────→│
     │  返回二维码    │←──────────────│               │               │
     │←───────────────│               │               │               │
     │               │               │               │  上传二维码     │
     │               │               │←──────────────│               │
     │               │               │               │               │
     │               │               │  前端展示二维码│               │
     │               │               │───────────────→│     扫码       │
     │               │               │               │←──────────────│
     │  扫码确认     │               │               │               │
     │←───────────────│               │               │               │
     │  登录成功     │               │               │               │
     │───────────────→│               │               │               │
     │               │  wechat_online callback       │               │
     │               │───────────────→│               │               │
     │               │               │  更新状态     │               │
     │               │               │───────────────→│   完成        │

4.2 详细步骤

步骤 参与者 操作 API/协议
1 微信 掉线检测 -
2 节点 回调通知中控 POST /callback
3 中控 触发Webhook告警 HTTP
4 客户端 接收告警 POST /webhook/relogin
5 客户端 请求节点二维码 GET /api/wechat/qrcode
6 节点 返回二维码图片 HTTP
7 客户端 上传二维码到中控 POST /callback/relogin/qrcode
8 中控 存储并通知前端 WebSocket/轮询
9 前端 展示二维码 -
10 用户 扫码确认 -
11 微信 登录成功 -
12 节点 回调通知中控 POST /callback
13 中控 更新节点状态 -

5. 数据库设计

5.1 新增表

-- 节点重登录状态表
CREATE TABLE node_relogin_status (
    id SERIAL PRIMARY KEY,
    node_id VARCHAR(50) UNIQUE NOT NULL,
    status VARCHAR(20) DEFAULT 'idle',
    qrcode_base64 TEXT,
    qrcode_expires_at TIMESTAMP,
    error_message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 客户端配置表
CREATE TABLE relogin_clients (
    id SERIAL PRIMARY KEY,
    client_name VARCHAR(100) NOT NULL,
    webhook_url VARCHAR(500) NOT NULL,
    secret_key VARCHAR(100),
    enabled BOOLEAN DEFAULT true,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

5.2 状态枚举

状态 说明
idle 空闲,无重登录任务
waiting_qrcode 等待获取二维码
qrcode_ready 二维码已就绪
scanned 已扫码,待确认
confirmed 已确认,登录中
completed 登录完成
failed 登录失败

6. API 接口详细设计

6.1 回调接口 - 接收二维码

POST /api/v1/callback/relogin/qrcode

请求体:

{
    "node_id": "wx1",
    "qrcode_base64": "data:image/png;base64,iVBORw0KGgo...",
    "expires_in": 120
}

响应:

{
    "success": true,
    "message": "二维码已接收"
}

6.2 查询重登录状态

GET /api/v1/nodes/{node_id}/relogin/status

响应:

{
    "success": true,
    "data": {
        "node_id": "wx1",
        "status": "qrcode_ready",
        "qrcode_base64": "data:image/png;base64,...",
        "qrcode_expires_at": "2026-04-07T15:30:00",
        "created_at": "2026-04-07T15:00:00"
    }
}

6.3 客户端注册

POST /api/v1/relogin/clients

请求体:

{
    "client_name": "服务器1",
    "webhook_url": "http://192.168.1.100:8081/webhook/relogin",
    "secret_key": "optional_secret"
}

6.4 客户端列表

GET /api/v1/relogin/clients

7. 安全考虑

7.1 客户端认证

  • 客户端注册时分配 secret_key
  • 回调接口需要携带签名验证
  • 中控可配置允许的客户端IP白名单

7.2 回调签名验证

import hmac
import hashlib

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

8. 文件结构

wxauto_api/
├── plugins/
│   └── wxautorelogin_plugin.py    # 重登录插件
├── api/
│   └── relogin.py                 # 重登录相关API
├── services/
│   └── relogin_service.py         # 重登录服务
└── doc/
    └── wxautorelogin/
        ├── README.md              # 本文档
        ├── CLIENT.md              # 客户端开发指南
        └── API.md                 # API接口文档

wxauto-relogin-client/
├── client/
│   ├── __init__.py
│   ├── webhook_server.py         # Webhook接收服务
│   ├── qrcode_handler.py          # 二维码处理
│   └── config.py                 # 配置
├── requirements.txt
└── README.md

9. 可行性结论

9.1 技术可行性: 可行

  1. wxauto节点已提供QR码接口 - 通过 /api/wechat/qrcode 获取
  2. 中控已有回调机制 - 可复用现有 callback 系统
  3. 前端支持实时更新 - 可通过轮询或WebSocket展示二维码

9.2 实施难度:🟡 中等

  1. 需要开发客户端程序
  2. 需要新增API接口
  3. 需要前端新增重登录页面

9.3 建议实施顺序

  1. Phase 1: 中控端API开发
  2. Phase 2: 客户端程序开发
  3. Phase 3: 前端页面开发
  4. Phase 4: 整体联调测试

10. 后续优化方向

  • 支持短信/邮件通知
  • 支持多客户端负载均衡
  • 支持扫码历史记录
  • 支持自动重试机制