# 扩展功能API文档 ## 概述 扩展功能允许开发者通过Webhook和开放API将平台功能与自己的业务系统对接,实现自动化业务流程。 ## 功能特性 - **Webhook回调**: 实时接收平台事件通知 - **开放API**: 通过API密钥访问平台功能 - **签名验证**: 确保请求安全可靠 - **权限控制**: 细粒度的API访问权限管理 --- ## 一、Webhook配置 ### 1.1 创建Webhook **接口**: `POST /api/v1/dev/extension/webhooks` **请求参数**: ```json { "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` **响应示例**: ```json { "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请求: ```json { "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` **请求参数**: ```json { "application_id": 1, "name": "商城对接", "permissions": ["user.read", "user.recharge"], "expires_at": "2025-12-31T23:59:59Z" } ``` **参数说明**: - `application_id` (必填): 应用ID - `name` (必填): 密钥名称 - `permissions` (可选): 权限列表 - `expires_at` (可选): 过期时间 **响应示例**: ```json { "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 ``` **签名算法**: ```javascript // 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示例**: ```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` **响应示例**: ```json { "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` **请求参数**: ```json { "amount": 100, "type": "points", "description": "商城充值" } ``` **参数说明**: - `amount` (必填): 充值数量 - `type` (必填): 充值类型 - `points`: 充值积分 - `days`: 充值天数 - `description` (可选): 充值说明 #### 4.2.4 扣除用户余额 **接口**: `POST /api/v1/ext/user/:userId/deduct` **请求参数**: ```json { "amount": 50, "type": "points", "description": "购买商品" } ``` #### 4.2.5 更新用户积分 **接口**: `POST /api/v1/ext/user/:userId/points` **请求参数**: ```json { "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` **请求参数**: ```json { "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` **请求参数**: ```json { "user_id": 123, "title": "系统通知", "content": "您的充值已到账", "type": "system" } ``` #### 4.4.2 批量发送通知 **接口**: `POST /api/v1/ext/notification/batch` **请求参数**: ```json { "title": "系统公告", "content": "系统将于今晚维护", "type": "announcement" } ``` ### 4.5 应用信息接口 #### 4.5.1 获取应用信息 **接口**: `GET /api/v1/ext/app/info` #### 4.5.2 获取应用统计 **接口**: `GET /api/v1/ext/app/stats` **响应示例**: ```json { "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示例 ```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示例 ```javascript 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等工具,参考本文档中的签名算法构造请求。 --- ## 十、技术支持 如有问题,请通过以下方式获取帮助: - 查看平台文档 - 提交工单 - 联系技术支持