Files
verify/backend/docs/EXTENSION_API.md
T
2026-04-27 17:22:56 +08:00

14 KiB

扩展功能API文档

概述

扩展功能允许开发者通过Webhook和开放API将平台功能与自己的业务系统对接,实现自动化业务流程。

功能特性

  • Webhook回调: 实时接收平台事件通知
  • 开放API: 通过API密钥访问平台功能
  • 签名验证: 确保请求安全可靠
  • 权限控制: 细粒度的API访问权限管理

一、Webhook配置

1.1 创建Webhook

接口: POST /api/v1/dev/extension/webhooks

请求参数:

{
  "application_id": 1,
  "name": "商城系统",
  "url": "https://your-server.com/webhook",
  "secret_key": "your_secret_key",
  "events": ["user.registered", "user.recharged"],
  "retry_count": 3,
  "timeout": 10
}

参数说明:

  • application_id (必填): 应用ID
  • name (必填): Webhook名称
  • url (必填): 回调URL
  • secret_key (可选): 密钥,用于验证回调请求
  • events (必填): 订阅的事件类型数组
  • retry_count (可选): 重试次数,默认3次
  • timeout (可选): 超时时间(秒),默认10秒

1.2 查询Webhook列表

接口: GET /api/v1/dev/extension/webhooks?application_id=1

响应示例:

{
  "code": 200,
  "data": [
    {
      "id": 1,
      "application_id": 1,
      "name": "商城系统",
      "url": "https://your-server.com/webhook",
      "secret_key": "your_secret_key",
      "events": "[\"user.registered\",\"user.recharged\"]",
      "status": "active",
      "retry_count": 3,
      "timeout": 10,
      "created_at": "2024-01-01T00:00:00Z"
    }
  ]
}

1.3 更新Webhook

接口: PUT /api/v1/dev/extension/webhooks/:id

请求参数: 同创建Webhook

1.4 删除Webhook

接口: DELETE /api/v1/dev/extension/webhooks/:id

1.5 测试Webhook

接口: POST /api/v1/dev/extension/webhooks/:id/test

1.6 查看Webhook日志

接口: GET /api/v1/dev/extension/webhooks/logs?webhook_id=1


二、Webhook事件

2.1 支持的事件类型

事件代码 事件名称 触发时机
user.registered 用户注册 新用户注册成功时
user.login 用户登录 用户登录成功时
user.recharged 用户充值 用户充值成功时
user.expired 用户到期 用户会员到期时
card.used 卡密使用 卡密被使用时
card.expired 卡密过期 卡密过期时
abnormal.detected 异常检测 检测到异常行为时

2.2 回调数据格式

当事件触发时,平台会向配置的URL发送POST请求:

{
  "event": "user.registered",
  "timestamp": 1234567890,
  "data": {
    "user_id": 123,
    "username": "testuser",
    "email": "test@example.com",
    "application_id": 1
  }
}

2.3 验证回调请求

如果配置了secret_key,平台会在请求头中添加:

X-Webhook-Secret: your_secret_key

您的服务器应验证此头部以确保请求来自平台。


三、API密钥管理

3.1 创建API密钥

接口: POST /api/v1/dev/extension/api-keys

请求参数:

{
  "application_id": 1,
  "name": "商城对接",
  "permissions": ["user.read", "user.recharge"],
  "expires_at": "2025-12-31T23:59:59Z"
}

参数说明:

  • application_id (必填): 应用ID
  • name (必填): 密钥名称
  • permissions (可选): 权限列表
  • expires_at (可选): 过期时间

响应示例:

{
  "code": 200,
  "data": {
    "id": 1,
    "application_id": 1,
    "name": "商城对接",
    "access_key": "abc123...",
    "secret_key": "xyz789...",
    "permissions": "[\"user.read\",\"user.recharge\"]",
    "status": "active",
    "created_at": "2024-01-01T00:00:00Z"
  }
}

重要: secret_key只在创建时返回一次,请妥善保存!

3.2 查询API密钥列表

接口: GET /api/v1/dev/extension/api-keys?application_id=1

3.3 更新API密钥

接口: PUT /api/v1/dev/extension/api-keys/:id

3.4 删除API密钥

接口: DELETE /api/v1/dev/extension/api-keys/:id

3.5 重新生成密钥

接口: POST /api/v1/dev/extension/api-keys/:id/regenerate

注意: 重新生成后,旧密钥立即失效!


四、开放API接口

4.1 认证方式

所有开放API请求都需要进行签名认证:

请求头:

X-Access-Key: your_access_key
X-Signature: calculated_signature
X-Timestamp: 1234567890

签名算法:

// 1. 构造签名字符串
const stringToSign = METHOD + PATH + TIMESTAMP + BODY

// 示例
const method = "POST"
const path = "/api/v1/ext/user/123/recharge"
const timestamp = "1234567890"
const body = JSON.stringify({
  "amount": 100,
  "type": "points",
  "description": "商城充值"
})

const stringToSign = method + path + timestamp + body
// 结果: "POST/api/v1/ext/user/123/recharge1234567890{\"amount\":100,\"type\":\"points\",\"description\":\"商城充值\"}"

// 2. 计算签名
const signature = HMAC-SHA256(secretKey, stringToSign)

Python示例:

import hmac
import hashlib
import time
import json

def calculate_signature(secret_key, method, path, timestamp, body):
    string_to_sign = method + path + str(timestamp) + body
    signature = hmac.new(
        secret_key.encode('utf-8'),
        string_to_sign.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return signature

# 使用示例
access_key = "your_access_key"
secret_key = "your_secret_key"
method = "POST"
path = "/api/v1/ext/user/123/recharge"
timestamp = int(time.time())
body = json.dumps({
    "amount": 100,
    "type": "points",
    "description": "商城充值"
})

signature = calculate_signature(secret_key, method, path, timestamp, body)

headers = {
    "X-Access-Key": access_key,
    "X-Signature": signature,
    "X-Timestamp": str(timestamp),
    "Content-Type": "application/json"
}

4.2 用户相关接口

4.2.1 查询用户信息

接口: GET /api/v1/ext/user/:userId

响应示例:

{
  "code": 200,
  "data": {
    "id": 123,
    "username": "testuser",
    "email": "test@example.com",
    "points": 1000,
    "level": 1,
    "status": "active",
    "expiry_at": "2024-12-31T23:59:59Z",
    "last_login_at": "2024-01-01T12:00:00Z",
    "created_at": "2024-01-01T00:00:00Z"
  }
}

4.2.2 查询用户列表

接口: GET /api/v1/ext/users?page=1&page_size=20&status=active&search=test

参数说明:

  • page: 页码,默认1
  • page_size: 每页数量,默认20
  • status: 用户状态筛选
  • search: 搜索关键词(用户名或邮箱)

4.2.3 为用户充值

接口: POST /api/v1/ext/user/:userId/recharge

请求参数:

{
  "amount": 100,
  "type": "points",
  "description": "商城充值"
}

参数说明:

  • amount (必填): 充值数量
  • type (必填): 充值类型
    • points: 充值积分
    • days: 充值天数
  • description (可选): 充值说明

4.2.4 扣除用户余额

接口: POST /api/v1/ext/user/:userId/deduct

请求参数:

{
  "amount": 50,
  "type": "points",
  "description": "购买商品"
}

4.2.5 更新用户积分

接口: POST /api/v1/ext/user/:userId/points

请求参数:

{
  "points": 500
}

4.3 卡密相关接口

4.3.1 查询卡密列表

接口: GET /api/v1/ext/cards?page=1&page_size=20&status=unused&card_type_id=1

4.3.2 生成卡密

接口: POST /api/v1/ext/cards/generate

请求参数:

{
  "card_type_id": 1,
  "count": 10
}

4.3.3 查询卡密详情

接口: GET /api/v1/ext/card/:cardId

4.4 通知相关接口

4.4.1 发送通知

接口: POST /api/v1/ext/notification

请求参数:

{
  "user_id": 123,
  "title": "系统通知",
  "content": "您的充值已到账",
  "type": "system"
}

4.4.2 批量发送通知

接口: POST /api/v1/ext/notification/batch

请求参数:

{
  "title": "系统公告",
  "content": "系统将于今晚维护",
  "type": "announcement"
}

4.5 应用信息接口

4.5.1 获取应用信息

接口: GET /api/v1/ext/app/info

4.5.2 获取应用统计

接口: GET /api/v1/ext/app/stats

响应示例:

{
  "code": 200,
  "data": {
    "user_count": 1000,
    "active_user_count": 800,
    "card_count": 500,
    "used_card_count": 300
  }
}

五、权限说明

5.1 可用权限列表

权限代码 权限名称 说明
user.read 查看用户 查询用户信息和列表
user.recharge 用户充值 为用户充值积分或天数
user.deduct 用户扣费 扣除用户积分或天数
card.read 查看卡密 查询卡密信息和列表
card.generate 生成卡密 生成新的卡密
notification.send 发送通知 发送用户通知

六、错误码说明

错误码 说明
200 成功
400 请求参数错误
401 认证失败(缺少认证信息、签名错误、密钥无效等)
403 权限不足
404 资源不存在
500 服务器内部错误

七、最佳实践

7.1 安全建议

  1. 妥善保管密钥: Secret Key只在创建时显示一次,请立即保存
  2. 定期更换密钥: 建议定期重新生成API密钥
  3. 最小权限原则: 只授予必要的权限
  4. 验证Webhook: 验证回调请求的来源和完整性
  5. 使用HTTPS: 确保所有通信都使用HTTPS

7.2 性能优化

  1. 批量操作: 使用批量接口减少请求次数
  2. 缓存数据: 合理缓存用户信息等数据
  3. 异步处理: Webhook回调建议异步处理业务逻辑

7.3 错误处理

  1. 重试机制: 实现请求重试逻辑,处理网络异常
  2. 日志记录: 记录所有API请求和响应,便于排查问题
  3. 超时设置: 合理设置请求超时时间

八、完整示例

8.1 Python示例

import requests
import hmac
import hashlib
import time
import json

class ExtensionAPI:
    def __init__(self, access_key, secret_key, base_url="http://localhost:8080"):
        self.access_key = access_key
        self.secret_key = secret_key
        self.base_url = base_url
    
    def _calculate_signature(self, method, path, timestamp, body=""):
        string_to_sign = method + path + str(timestamp) + body
        signature = hmac.new(
            self.secret_key.encode('utf-8'),
            string_to_sign.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        return signature
    
    def _get_headers(self, method, path, body=""):
        timestamp = int(time.time())
        signature = self._calculate_signature(method, path, timestamp, body)
        return {
            "X-Access-Key": self.access_key,
            "X-Signature": signature,
            "X-Timestamp": str(timestamp),
            "Content-Type": "application/json"
        }
    
    def get_user(self, user_id):
        path = f"/api/v1/ext/user/{user_id}"
        headers = self._get_headers("GET", path)
        response = requests.get(f"{self.base_url}{path}", headers=headers)
        return response.json()
    
    def recharge_user(self, user_id, amount, recharge_type, description=""):
        path = f"/api/v1/ext/user/{user_id}/recharge"
        body = json.dumps({
            "amount": amount,
            "type": recharge_type,
            "description": description
        })
        headers = self._get_headers("POST", path, body)
        response = requests.post(f"{self.base_url}{path}", headers=headers, data=body)
        return response.json()

# 使用示例
api = ExtensionAPI("your_access_key", "your_secret_key")

# 查询用户
user = api.get_user(123)
print(user)

# 为用户充值100积分
result = api.recharge_user(123, 100, "points", "商城充值")
print(result)

8.2 Node.js示例

const crypto = require('crypto');
const axios = require('axios');

class ExtensionAPI {
  constructor(accessKey, secretKey, baseUrl = 'http://localhost:8080') {
    this.accessKey = accessKey;
    this.secretKey = secretKey;
    this.baseUrl = baseUrl;
  }

  calculateSignature(method, path, timestamp, body = '') {
    const stringToSign = method + path + timestamp + body;
    return crypto
      .createHmac('sha256', this.secretKey)
      .update(stringToSign)
      .digest('hex');
  }

  getHeaders(method, path, body = '') {
    const timestamp = Math.floor(Date.now() / 1000);
    const signature = this.calculateSignature(method, path, timestamp, body);
    return {
      'X-Access-Key': this.accessKey,
      'X-Signature': signature,
      'X-Timestamp': timestamp.toString(),
      'Content-Type': 'application/json'
    };
  }

  async getUser(userId) {
    const path = `/api/v1/ext/user/${userId}`;
    const headers = this.getHeaders('GET', path);
    const response = await axios.get(`${this.baseUrl}${path}`, { headers });
    return response.data;
  }

  async rechargeUser(userId, amount, type, description = '') {
    const path = `/api/v1/ext/user/${userId}/recharge`;
    const body = JSON.stringify({ amount, type, description });
    const headers = this.getHeaders('POST', path, body);
    const response = await axios.post(`${this.baseUrl}${path}`, body, { headers });
    return response.data;
  }
}

// 使用示例
const api = new ExtensionAPI('your_access_key', 'your_secret_key');

// 查询用户
api.getUser(123).then(user => console.log(user));

// 为用户充值100积分
api.rechargeUser(123, 100, 'points', '商城充值').then(result => console.log(result));

九、常见问题

Q1: 签名验证失败怎么办?

A: 请检查以下几点:

  1. 确保使用正确的Secret Key
  2. 确保时间戳是当前Unix时间戳(秒级)
  3. 确保签名字符串的拼接顺序正确:METHOD + PATH + TIMESTAMP + BODY
  4. 确保Body是原始JSON字符串,不要格式化或添加空格

Q2: Webhook回调失败怎么办?

A:

  1. 检查回调URL是否可访问
  2. 查看Webhook日志了解失败原因
  3. 确保服务器能正确处理POST请求
  4. 检查是否设置了正确的超时时间

Q3: API密钥泄露了怎么办?

A: 立即删除旧密钥并创建新密钥,或者使用"重新生成"功能。

Q4: 如何测试API接口?

A: 可以使用Postman、curl等工具,参考本文档中的签名算法构造请求。


十、技术支持

如有问题,请通过以下方式获取帮助:

  • 查看平台文档
  • 提交工单
  • 联系技术支持