Initial commit: 网络验证平台
This commit is contained in:
@@ -0,0 +1,936 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"verification-platform-backend/internal/database"
|
||||
"verification-platform-backend/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
database.Init()
|
||||
db := database.DB
|
||||
|
||||
log.Println("开始初始化扩展API文档...")
|
||||
|
||||
var category model.DocCategory
|
||||
result := db.Where("slug = ?", "extension-api").First(&category)
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
category = model.DocCategory{
|
||||
Name: "扩展API",
|
||||
Slug: "extension-api",
|
||||
Description: "开放API文档,供开发者在自己的服务器集成平台功能",
|
||||
Icon: "code",
|
||||
Status: "active",
|
||||
Sort: 100,
|
||||
}
|
||||
if err := db.Create(&category).Error; err != nil {
|
||||
log.Fatalf("创建文档分类失败: %v", err)
|
||||
}
|
||||
log.Println("创建文档分类成功")
|
||||
} else {
|
||||
log.Println("文档分类已存在")
|
||||
}
|
||||
|
||||
docs := []struct {
|
||||
Title string
|
||||
Slug string
|
||||
Content string
|
||||
Sort int
|
||||
}{
|
||||
{
|
||||
Title: "扩展API概述",
|
||||
Slug: "extension-api-overview",
|
||||
Content: `# 扩展API概述
|
||||
|
||||
扩展API允许开发者在自己的服务器上集成平台功能,实现自定义的业务逻辑。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- **用户管理**: 查询用户信息、充值、扣费等操作
|
||||
- **卡密管理**: 查询卡密、生成卡密
|
||||
- **消息通知**: 向用户发送通知消息
|
||||
- **应用管理**: 获取应用信息和统计数据
|
||||
- **云端变量**: 读写用户和应用级别的云端变量
|
||||
|
||||
## 认证方式
|
||||
|
||||
所有API请求需要进行签名认证,请求头需要包含以下字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| X-Access-Key | API密钥的Access Key |
|
||||
| X-Signature | 请求签名 |
|
||||
| X-Timestamp | 请求时间戳(秒级) |
|
||||
|
||||
## 签名算法
|
||||
|
||||
签名生成步骤:
|
||||
|
||||
1. 拼接签名字符串: ` + "`METHOD + PATH + TIMESTAMP + BODY`" + `
|
||||
2. 使用Secret Key对签名字符串进行HMAC-SHA256签名
|
||||
3. 将签名结果转换为十六进制字符串
|
||||
|
||||
` + "```javascript" + `
|
||||
// JavaScript示例
|
||||
const crypto = require('crypto');
|
||||
|
||||
function generateSignature(method, path, timestamp, body, secretKey) {
|
||||
const stringToSign = method + path + timestamp + body;
|
||||
const hmac = crypto.createHmac('sha256', secretKey);
|
||||
hmac.update(stringToSign);
|
||||
return hmac.digest('hex');
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
## 请求限制
|
||||
|
||||
- 时间戳有效期:5分钟
|
||||
- 请求频率:根据套餐限制
|
||||
|
||||
## 创建API密钥
|
||||
|
||||
1. 进入「扩展配置」页面
|
||||
2. 切换到「API密钥」标签
|
||||
3. 点击「创建密钥」按钮
|
||||
4. 选择应用并配置权限
|
||||
5. 保存Access Key和Secret Key
|
||||
|
||||
> ⚠️ **注意**: Secret Key只在创建时显示一次,请妥善保存!
|
||||
`,
|
||||
Sort: 1,
|
||||
},
|
||||
{
|
||||
Title: "用户管理",
|
||||
Slug: "extension-api-user",
|
||||
Content: `# 用户管理
|
||||
|
||||
## 获取用户信息
|
||||
|
||||
获取指定用户的详细信息。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/user/:userId
|
||||
` + "```" + `
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| X-Access-Key | string | 是 | Access Key |
|
||||
| X-Signature | string | 是 | 请求签名 |
|
||||
| X-Timestamp | string | 是 | 时间戳 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"email": "test@example.com",
|
||||
"status": "active",
|
||||
"expiry_at": "2025-12-31T23:59:59Z",
|
||||
"last_login_at": "2024-01-15T10:30:00Z",
|
||||
"is_trial_user": false,
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.read`" + `
|
||||
|
||||
---
|
||||
|
||||
## 获取用户列表
|
||||
|
||||
获取应用下的用户列表。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/users
|
||||
` + "```" + `
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20 |
|
||||
| status | string | 否 | 状态筛选 |
|
||||
| search | string | 否 | 搜索关键词 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"users": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_page": 5
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.list`" + `
|
||||
|
||||
---
|
||||
|
||||
## 用户充值
|
||||
|
||||
为用户充值时长。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/user/:userId/recharge
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"amount": 30,
|
||||
"type": "days",
|
||||
"description": "在线充值"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| amount | int | 是 | 充值数量 |
|
||||
| type | string | 是 | 类型:days(天数) |
|
||||
| description | string | 否 | 描述说明 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "充值成功",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"expiry_at": "2025-12-31T23:59:59Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.recharge`" + `
|
||||
|
||||
---
|
||||
|
||||
## 用户扣费
|
||||
|
||||
扣除用户时长。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/user/:userId/deduct
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"amount": 10,
|
||||
"type": "days",
|
||||
"description": "消费扣费"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "扣除成功",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"expiry_at": "2025-12-21T23:59:59Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.deduct`" + `
|
||||
|
||||
---
|
||||
|
||||
## 获取用户变量
|
||||
|
||||
获取用户的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/user/:userId/variables
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"vip_level": {
|
||||
"value": "3",
|
||||
"scope": "user"
|
||||
},
|
||||
"game_score": {
|
||||
"value": "1000",
|
||||
"scope": "user"
|
||||
}
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.variables`" + `
|
||||
|
||||
---
|
||||
|
||||
## 更新用户变量
|
||||
|
||||
更新用户的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/user/:userId/variables
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"variables": {
|
||||
"vip_level": "5",
|
||||
"game_score": "2000"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "更新成功"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`user.variables`" + `
|
||||
`,
|
||||
Sort: 2,
|
||||
},
|
||||
{
|
||||
Title: "卡密管理",
|
||||
Slug: "extension-api-card",
|
||||
Content: `# 卡密管理
|
||||
|
||||
## 获取卡密列表
|
||||
|
||||
获取应用下的卡密列表。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/cards
|
||||
` + "```" + `
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20 |
|
||||
| status | string | 否 | 状态筛选:unused/used/disabled |
|
||||
| card_type_id | int | 否 | 卡密类型ID |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"cards": [
|
||||
{
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"card_type_id": 1,
|
||||
"status": "unused",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_page": 5
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`card.read`" + `
|
||||
|
||||
---
|
||||
|
||||
## 生成卡密
|
||||
|
||||
批量生成卡密。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/cards/generate
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"card_type_id": 1,
|
||||
"count": 10
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| card_type_id | int | 是 | 卡密类型ID |
|
||||
| count | int | 是 | 生成数量 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "生成成功",
|
||||
"count": 10,
|
||||
"cards": [
|
||||
{
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"status": "unused"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`card.generate`" + `
|
||||
|
||||
---
|
||||
|
||||
## 获取卡密详情
|
||||
|
||||
获取单个卡密的详细信息。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/card/:cardId
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"card_type_id": 1,
|
||||
"status": "unused",
|
||||
"used_at": null,
|
||||
"app_user_id": null,
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`card.read`" + `
|
||||
`,
|
||||
Sort: 3,
|
||||
},
|
||||
{
|
||||
Title: "消息通知",
|
||||
Slug: "extension-api-notification",
|
||||
Content: `# 消息通知
|
||||
|
||||
## 发送单个通知
|
||||
|
||||
向指定用户发送通知消息。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/notification
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"user_id": 1,
|
||||
"title": "系统通知",
|
||||
"content": "您的账户已充值成功!",
|
||||
"type": "info"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| user_id | int | 是 | 用户ID |
|
||||
| title | string | 是 | 通知标题 |
|
||||
| content | string | 是 | 通知内容 |
|
||||
| type | string | 否 | 类型:info/warning/error |
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "发送成功",
|
||||
"notification": {
|
||||
"id": 1,
|
||||
"title": "系统通知",
|
||||
"content": "您的账户已充值成功!"
|
||||
}
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`notification.send`" + `
|
||||
|
||||
---
|
||||
|
||||
## 批量发送通知
|
||||
|
||||
向所有用户发送通知消息。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/notification/batch
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"title": "系统公告",
|
||||
"content": "系统将于今晚进行维护...",
|
||||
"type": "warning"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "发送成功",
|
||||
"notification": {
|
||||
"id": 1,
|
||||
"title": "系统公告",
|
||||
"content": "系统将于今晚进行维护..."
|
||||
}
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`notification.send`" + `
|
||||
`,
|
||||
Sort: 4,
|
||||
},
|
||||
{
|
||||
Title: "应用管理",
|
||||
Slug: "extension-api-app",
|
||||
Content: `# 应用管理
|
||||
|
||||
## 获取应用信息
|
||||
|
||||
获取当前应用的基本信息。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/app/info
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "我的应用",
|
||||
"description": "应用描述",
|
||||
"billing_type": "subscription",
|
||||
"encrypt_type": "aes",
|
||||
"bind_type": "device",
|
||||
"max_devices": 3,
|
||||
"multi_open": false,
|
||||
"enable_trial": true,
|
||||
"trial_duration": 7,
|
||||
"status": "active",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`app.info`" + `
|
||||
|
||||
---
|
||||
|
||||
## 获取应用统计
|
||||
|
||||
获取应用的统计数据。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/app/stats
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"user_count": 1000,
|
||||
"active_user_count": 500,
|
||||
"card_count": 200,
|
||||
"used_card_count": 150
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`app.stats`" + `
|
||||
|
||||
---
|
||||
|
||||
## 获取应用变量
|
||||
|
||||
获取应用级别的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
GET /api/v1/ext/app/variables
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"app_version": "1.0.0",
|
||||
"maintenance_mode": "false",
|
||||
"announcement": "欢迎使用本应用"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`app.variables`" + `
|
||||
|
||||
---
|
||||
|
||||
## 更新应用变量
|
||||
|
||||
更新应用级别的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
` + "```" + `
|
||||
POST /api/v1/ext/app/variables
|
||||
` + "```" + `
|
||||
|
||||
### 请求体
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"variables": {
|
||||
"app_version": "1.0.1",
|
||||
"maintenance_mode": "true",
|
||||
"announcement": "系统维护中,请稍后..."
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "更新成功"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 所需权限
|
||||
|
||||
- ` + "`app.variables`" + `
|
||||
`,
|
||||
Sort: 5,
|
||||
},
|
||||
{
|
||||
Title: "代码示例",
|
||||
Slug: "extension-api-examples",
|
||||
Content: `# 代码示例
|
||||
|
||||
## JavaScript/Node.js
|
||||
|
||||
` + "```javascript" + `
|
||||
const crypto = require('crypto');
|
||||
const axios = require('axios');
|
||||
|
||||
const ACCESS_KEY = 'your_access_key';
|
||||
const SECRET_KEY = 'your_secret_key';
|
||||
const BASE_URL = 'https://your-domain.com/api/v1/ext';
|
||||
|
||||
// 生成签名
|
||||
function generateSignature(method, path, timestamp, body) {
|
||||
const bodyStr = body ? JSON.stringify(body) : '';
|
||||
const stringToSign = method + path + timestamp + bodyStr;
|
||||
const hmac = crypto.createHmac('sha256', SECRET_KEY);
|
||||
hmac.update(stringToSign);
|
||||
return hmac.digest('hex');
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
async function request(method, path, body = null) {
|
||||
const timestamp = Math.floor(Date.now() / 1000).toString();
|
||||
const signature = generateSignature(method, path, timestamp, body);
|
||||
|
||||
const headers = {
|
||||
'X-Access-Key': ACCESS_KEY,
|
||||
'X-Signature': signature,
|
||||
'X-Timestamp': timestamp,
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
const config = {
|
||||
method,
|
||||
url: BASE_URL + path,
|
||||
headers
|
||||
};
|
||||
|
||||
if (body) {
|
||||
config.data = body;
|
||||
}
|
||||
|
||||
const response = await axios(config);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
async function main() {
|
||||
// 获取用户信息
|
||||
const user = await request('GET', '/user/1');
|
||||
console.log('用户信息:', user);
|
||||
|
||||
// 用户充值
|
||||
const result = await request('POST', '/user/1/recharge', {
|
||||
amount: 30,
|
||||
type: 'days',
|
||||
description: '在线充值'
|
||||
});
|
||||
console.log('充值结果:', result);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
` + "```" + `
|
||||
|
||||
## Python
|
||||
|
||||
` + "```python" + `
|
||||
import hmac
|
||||
import hashlib
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
|
||||
ACCESS_KEY = 'your_access_key'
|
||||
SECRET_KEY = 'your_secret_key'
|
||||
BASE_URL = 'https://your-domain.com/api/v1/ext'
|
||||
|
||||
def generate_signature(method, path, timestamp, body=''):
|
||||
string_to_sign = method + path + timestamp + body
|
||||
signature = hmac.new(
|
||||
SECRET_KEY.encode('utf-8'),
|
||||
string_to_sign.encode('utf-8'),
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
return signature
|
||||
|
||||
def request(method, path, body=None):
|
||||
timestamp = str(int(time.time()))
|
||||
body_str = json.dumps(body) if body else ''
|
||||
signature = generate_signature(method, path, timestamp, body_str)
|
||||
|
||||
headers = {
|
||||
'X-Access-Key': ACCESS_KEY,
|
||||
'X-Signature': signature,
|
||||
'X-Timestamp': timestamp,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
url = BASE_URL + path
|
||||
response = requests.request(method, url, headers=headers, json=body)
|
||||
return response.json()
|
||||
|
||||
# 使用示例
|
||||
if __name__ == '__main__':
|
||||
# 获取用户信息
|
||||
user = request('GET', '/user/1')
|
||||
print('用户信息:', user)
|
||||
|
||||
# 用户充值
|
||||
result = request('POST', '/user/1/recharge', {
|
||||
'amount': 30,
|
||||
'type': 'days',
|
||||
'description': '在线充值'
|
||||
})
|
||||
print('充值结果:', result)
|
||||
` + "```" + `
|
||||
|
||||
## 在线充值集成示例
|
||||
|
||||
以下是一个完整的在线充值集成示例,展示如何实现用户在线支付后自动充值:
|
||||
|
||||
` + "```javascript" + `
|
||||
// 支付回调处理
|
||||
app.post('/payment/callback', async (req, res) => {
|
||||
const { order_id, user_id, amount, status } = req.body;
|
||||
|
||||
// 验证支付状态
|
||||
if (status !== 'success') {
|
||||
return res.json({ code: -1, message: '支付失败' });
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用扩展API为用户充值
|
||||
const result = await request('POST', '/user/' + user_id + '/recharge', {
|
||||
amount: Math.floor(amount), // 充值天数
|
||||
type: 'days',
|
||||
description: '在线支付充值 - 订单号: ' + order_id
|
||||
});
|
||||
|
||||
if (result.code === 0) {
|
||||
// 更新订单状态
|
||||
await updateOrderStatus(order_id, 'completed');
|
||||
res.json({ code: 0, message: '充值成功' });
|
||||
} else {
|
||||
res.json({ code: -1, message: result.message });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('充值失败:', error);
|
||||
res.json({ code: -1, message: '充值失败' });
|
||||
}
|
||||
});
|
||||
` + "```" + `
|
||||
`,
|
||||
Sort: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, docData := range docs {
|
||||
var existingDoc model.Doc
|
||||
result := db.Where("slug = ?", docData.Slug).First(&existingDoc)
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
doc := model.Doc{
|
||||
CategoryID: &category.ID,
|
||||
Title: docData.Title,
|
||||
Slug: docData.Slug,
|
||||
Content: docData.Content,
|
||||
Status: "published",
|
||||
Sort: docData.Sort,
|
||||
}
|
||||
if err := db.Create(&doc).Error; err != nil {
|
||||
log.Printf("创建文档 %s 失败: %v", docData.Title, err)
|
||||
} else {
|
||||
log.Printf("创建文档 %s 成功", docData.Title)
|
||||
}
|
||||
} else {
|
||||
existingDoc.Content = docData.Content
|
||||
existingDoc.Title = docData.Title
|
||||
db.Save(&existingDoc)
|
||||
log.Printf("文档 %s 已存在,已更新", docData.Title)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("扩展API文档初始化完成!")
|
||||
fmt.Println("\n文档列表:")
|
||||
fmt.Println("1. 扩展API概述")
|
||||
fmt.Println("2. 用户管理")
|
||||
fmt.Println("3. 卡密管理")
|
||||
fmt.Println("4. 消息通知")
|
||||
fmt.Println("5. 应用管理")
|
||||
fmt.Println("6. 代码示例")
|
||||
fmt.Println("\n请访问管理后台的文档管理页面查看和编辑这些文档。")
|
||||
}
|
||||
@@ -0,0 +1,852 @@
|
||||
-- 扩展API文档初始化脚本
|
||||
-- 运行方式: 在项目根目录执行 go run cmd/scripts/init_extension_docs.go
|
||||
|
||||
-- 首先创建扩展API文档分类
|
||||
INSERT INTO doc_categories (name, slug, description, icon, status, sort, created_at, updated_at)
|
||||
VALUES ('扩展API', 'extension-api', '开放API文档,供开发者在自己的服务器集成平台功能', 'code', 'active', 100, datetime('now'), datetime('now'));
|
||||
|
||||
-- 概述文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'扩展API概述',
|
||||
'extension-api-overview',
|
||||
'# 扩展API概述
|
||||
|
||||
扩展API允许开发者在自己的服务器上集成平台功能,实现自定义的业务逻辑。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- **用户管理**: 查询用户信息、充值、扣费等操作
|
||||
- **卡密管理**: 查询卡密、生成卡密
|
||||
- **消息通知**: 向用户发送通知消息
|
||||
- **应用管理**: 获取应用信息和统计数据
|
||||
- **云端变量**: 读写用户和应用级别的云端变量
|
||||
|
||||
## 认证方式
|
||||
|
||||
所有API请求需要进行签名认证,请求头需要包含以下字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| X-Access-Key | API密钥的Access Key |
|
||||
| X-Signature | 请求签名 |
|
||||
| X-Timestamp | 请求时间戳(秒级) |
|
||||
|
||||
## 签名算法
|
||||
|
||||
签名生成步骤:
|
||||
|
||||
1. 拼接签名字符串: `METHOD + PATH + TIMESTAMP + BODY`
|
||||
2. 使用Secret Key对签名字符串进行HMAC-SHA256签名
|
||||
3. 将签名结果转换为十六进制字符串
|
||||
|
||||
```javascript
|
||||
// JavaScript示例
|
||||
const crypto = require(''crypto'');
|
||||
|
||||
function generateSignature(method, path, timestamp, body, secretKey) {
|
||||
const stringToSign = method + path + timestamp + body;
|
||||
const hmac = crypto.createHmac(''sha256'', secretKey);
|
||||
hmac.update(stringToSign);
|
||||
return hmac.digest(''hex'');
|
||||
}
|
||||
```
|
||||
|
||||
## 请求限制
|
||||
|
||||
- 时间戳有效期:5分钟
|
||||
- 请求频率:根据套餐限制
|
||||
|
||||
## 创建API密钥
|
||||
|
||||
1. 进入「扩展配置」页面
|
||||
2. 切换到「API密钥」标签
|
||||
3. 点击「创建密钥」按钮
|
||||
4. 选择应用并配置权限
|
||||
5. 保存Access Key和Secret Key
|
||||
|
||||
> ⚠️ **注意**: Secret Key只在创建时显示一次,请妥善保存!
|
||||
',
|
||||
'published',
|
||||
1,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
|
||||
-- 用户管理API文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'用户管理',
|
||||
'extension-api-user',
|
||||
'# 用户管理
|
||||
|
||||
## 获取用户信息
|
||||
|
||||
获取指定用户的详细信息。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/user/:userId
|
||||
```
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| X-Access-Key | string | 是 | Access Key |
|
||||
| X-Signature | string | 是 | 请求签名 |
|
||||
| X-Timestamp | string | 是 | 时间戳 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"email": "test@example.com",
|
||||
"status": "active",
|
||||
"balance": 100.00,
|
||||
"expiry_at": "2024-12-31T23:59:59Z",
|
||||
"last_login_at": "2024-01-15T10:30:00Z",
|
||||
"is_trial_user": false,
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取用户列表
|
||||
|
||||
获取应用下的用户列表。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/users
|
||||
```
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20 |
|
||||
| status | string | 否 | 状态筛选 |
|
||||
| search | string | 否 | 搜索关键词 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"users": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_page": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 用户充值
|
||||
|
||||
为用户充值时长或余额。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/user/:userId/recharge
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": 100,
|
||||
"type": "days",
|
||||
"description": "在线充值"
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| amount | int | 是 | 充值数量 |
|
||||
| type | string | 是 | 类型:days(天数)或 balance(余额) |
|
||||
| description | string | 否 | 描述说明 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "充值成功",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"balance": 100.00,
|
||||
"expiry_at": "2024-12-31T23:59:59Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 用户扣费
|
||||
|
||||
扣除用户余额或时长。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/user/:userId/deduct
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": 50,
|
||||
"type": "balance",
|
||||
"description": "消费扣费"
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| amount | int | 是 | 扣除数量 |
|
||||
| type | string | 是 | 类型:days(天数)或 balance(余额) |
|
||||
| description | string | 否 | 描述说明 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "扣除成功",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"balance": 50.00
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取用户变量
|
||||
|
||||
获取用户的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/user/:userId/variables
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"vip_level": {
|
||||
"value": "3",
|
||||
"scope": "user"
|
||||
},
|
||||
"game_score": {
|
||||
"value": "1000",
|
||||
"scope": "user"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 更新用户变量
|
||||
|
||||
更新用户的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/user/:userId/variables
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"variables": {
|
||||
"vip_level": "5",
|
||||
"game_score": "2000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "更新成功"
|
||||
}
|
||||
}
|
||||
```
|
||||
',
|
||||
'published',
|
||||
2,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
|
||||
-- 卡密管理API文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'卡密管理',
|
||||
'extension-api-card',
|
||||
'# 卡密管理
|
||||
|
||||
## 获取卡密列表
|
||||
|
||||
获取应用下的卡密列表。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/cards
|
||||
```
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| page_size | int | 否 | 每页数量,默认20 |
|
||||
| status | string | 否 | 状态筛选:unused/used/disabled |
|
||||
| card_type_id | int | 否 | 卡密类型ID |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"cards": [
|
||||
{
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"card_type_id": 1,
|
||||
"status": "unused",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_page": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 生成卡密
|
||||
|
||||
批量生成卡密。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/cards/generate
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"card_type_id": 1,
|
||||
"count": 10
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| card_type_id | int | 是 | 卡密类型ID |
|
||||
| count | int | 是 | 生成数量 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "生成成功",
|
||||
"count": 10,
|
||||
"cards": [
|
||||
{
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"status": "unused"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取卡密详情
|
||||
|
||||
获取单个卡密的详细信息。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/card/:cardId
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"card_key": "ABCD1234EFGH5678",
|
||||
"card_type_id": 1,
|
||||
"status": "unused",
|
||||
"used_at": null,
|
||||
"app_user_id": null,
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
',
|
||||
'published',
|
||||
3,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
|
||||
-- 消息通知API文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'消息通知',
|
||||
'extension-api-notification',
|
||||
'# 消息通知
|
||||
|
||||
## 发送单个通知
|
||||
|
||||
向指定用户发送通知消息。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/notification
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": 1,
|
||||
"title": "系统通知",
|
||||
"content": "您的账户已充值成功!",
|
||||
"type": "info"
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| user_id | int | 是 | 用户ID |
|
||||
| title | string | 是 | 通知标题 |
|
||||
| content | string | 是 | 通知内容 |
|
||||
| type | string | 否 | 类型:info/warning/error |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "发送成功",
|
||||
"notification": {
|
||||
"id": 1,
|
||||
"title": "系统通知",
|
||||
"content": "您的账户已充值成功!"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 批量发送通知
|
||||
|
||||
向所有用户发送通知消息。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/notification/batch
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "系统公告",
|
||||
"content": "系统将于今晚进行维护...",
|
||||
"type": "warning"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "发送成功",
|
||||
"notification": {
|
||||
"id": 1,
|
||||
"title": "系统公告",
|
||||
"content": "系统将于今晚进行维护..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
',
|
||||
'published',
|
||||
4,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
|
||||
-- 应用管理API文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'应用管理',
|
||||
'extension-api-app',
|
||||
'# 应用管理
|
||||
|
||||
## 获取应用信息
|
||||
|
||||
获取当前应用的基本信息。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/app/info
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "我的应用",
|
||||
"description": "应用描述",
|
||||
"billing_type": "subscription",
|
||||
"encrypt_type": "aes",
|
||||
"bind_type": "device",
|
||||
"max_devices": 3,
|
||||
"multi_open": false,
|
||||
"enable_trial": true,
|
||||
"trial_balance": 7,
|
||||
"status": "active",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取应用统计
|
||||
|
||||
获取应用的统计数据。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/app/stats
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"user_count": 1000,
|
||||
"active_user_count": 500,
|
||||
"card_count": 200,
|
||||
"used_card_count": 150
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取应用变量
|
||||
|
||||
获取应用级别的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/v1/ext/app/variables
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"app_version": "1.0.0",
|
||||
"maintenance_mode": "false",
|
||||
"announcement": "欢迎使用本应用"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 更新应用变量
|
||||
|
||||
更新应用级别的云端变量。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
POST /api/v1/ext/app/variables
|
||||
```
|
||||
|
||||
### 请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"variables": {
|
||||
"app_version": "1.0.1",
|
||||
"maintenance_mode": "true",
|
||||
"announcement": "系统维护中,请稍后..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"message": "更新成功"
|
||||
}
|
||||
}
|
||||
```
|
||||
',
|
||||
'published',
|
||||
5,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
|
||||
-- 代码示例文档
|
||||
INSERT INTO docs (category_id, title, slug, content, status, sort, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM doc_categories WHERE slug = 'extension-api'),
|
||||
'代码示例',
|
||||
'extension-api-examples',
|
||||
'# 代码示例
|
||||
|
||||
## JavaScript/Node.js
|
||||
|
||||
```javascript
|
||||
const crypto = require(''crypto'');
|
||||
const axios = require(''axios'');
|
||||
|
||||
const ACCESS_KEY = ''your_access_key'';
|
||||
const SECRET_KEY = ''your_secret_key'';
|
||||
const BASE_URL = ''https://your-domain.com/api/v1/ext'';
|
||||
|
||||
// 生成签名
|
||||
function generateSignature(method, path, timestamp, body) {
|
||||
const bodyStr = body ? JSON.stringify(body) : '''';
|
||||
const stringToSign = method + path + timestamp + bodyStr;
|
||||
const hmac = crypto.createHmac(''sha256'', SECRET_KEY);
|
||||
hmac.update(stringToSign);
|
||||
return hmac.digest(''hex'');
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
async function request(method, path, body = null) {
|
||||
const timestamp = Math.floor(Date.now() / 1000).toString();
|
||||
const signature = generateSignature(method, path, timestamp, body);
|
||||
|
||||
const headers = {
|
||||
''X-Access-Key'': ACCESS_KEY,
|
||||
''X-Signature'': signature,
|
||||
''X-Timestamp'': timestamp,
|
||||
''Content-Type'': ''application/json''
|
||||
};
|
||||
|
||||
const config = {
|
||||
method,
|
||||
url: BASE_URL + path,
|
||||
headers
|
||||
};
|
||||
|
||||
if (body) {
|
||||
config.data = body;
|
||||
}
|
||||
|
||||
const response = await axios(config);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
async function main() {
|
||||
// 获取用户信息
|
||||
const user = await request(''GET'', ''/user/1'');
|
||||
console.log(''用户信息:'', user);
|
||||
|
||||
// 用户充值
|
||||
const result = await request(''POST'', ''/user/1/recharge'', {
|
||||
amount: 100,
|
||||
type: ''days'',
|
||||
description: ''在线充值''
|
||||
});
|
||||
console.log(''充值结果:'', result);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
```python
|
||||
import hmac
|
||||
import hashlib
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
|
||||
ACCESS_KEY = ''your_access_key''
|
||||
SECRET_KEY = ''your_secret_key''
|
||||
BASE_URL = ''https://your-domain.com/api/v1/ext''
|
||||
|
||||
def generate_signature(method, path, timestamp, body=''''):
|
||||
string_to_sign = method + path + timestamp + body
|
||||
signature = hmac.new(
|
||||
SECRET_KEY.encode(''utf-8''),
|
||||
string_to_sign.encode(''utf-8''),
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
return signature
|
||||
|
||||
def request(method, path, body=None):
|
||||
timestamp = str(int(time.time()))
|
||||
body_str = json.dumps(body) if body else ''''
|
||||
signature = generate_signature(method, path, timestamp, body_str)
|
||||
|
||||
headers = {
|
||||
''X-Access-Key'': ACCESS_KEY,
|
||||
''X-Signature'': signature,
|
||||
''X-Timestamp'': timestamp,
|
||||
''Content-Type'': ''application/json''
|
||||
}
|
||||
|
||||
url = BASE_URL + path
|
||||
response = requests.request(method, url, headers=headers, json=body)
|
||||
return response.json()
|
||||
|
||||
# 使用示例
|
||||
if __name__ == ''__main__'':
|
||||
# 获取用户信息
|
||||
user = request(''GET'', ''/user/1'')
|
||||
print(''用户信息:'', user)
|
||||
|
||||
# 用户充值
|
||||
result = request(''POST'', ''/user/1/recharge'', {
|
||||
''amount'': 100,
|
||||
''type'': ''days'',
|
||||
''description'': ''在线充值''
|
||||
})
|
||||
print(''充值结果:'', result)
|
||||
```
|
||||
|
||||
## 在线充值集成示例
|
||||
|
||||
以下是一个完整的在线充值集成示例,展示如何实现用户在线支付后自动充值:
|
||||
|
||||
```javascript
|
||||
// 支付回调处理
|
||||
app.post(''/payment/callback'', async (req, res) => {
|
||||
const { order_id, user_id, amount, status } = req.body;
|
||||
|
||||
// 验证支付状态
|
||||
if (status !== ''success'') {
|
||||
return res.json({ code: -1, message: ''支付失败'' });
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用扩展API为用户充值
|
||||
const result = await request(''POST'', ''/user/'' + user_id + ''/recharge'', {
|
||||
amount: parseFloat(amount),
|
||||
type: ''days'',
|
||||
description: ''在线支付充值 - 订单号: '' + order_id
|
||||
});
|
||||
|
||||
if (result.code === 200) {
|
||||
// 更新订单状态
|
||||
await updateOrderStatus(order_id, ''completed'');
|
||||
res.json({ code: 0, message: ''充值成功'' });
|
||||
} else {
|
||||
res.json({ code: -1, message: result.message });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(''充值失败:'', error);
|
||||
res.json({ code: -1, message: ''充值失败'' });
|
||||
}
|
||||
});
|
||||
```
|
||||
',
|
||||
'published',
|
||||
6,
|
||||
datetime('now'),
|
||||
datetime('now')
|
||||
);
|
||||
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"verification-platform-backend/internal/database"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
database.Init()
|
||||
db := database.DB
|
||||
|
||||
log.Println("开始迁移:统一收费模式为余额")
|
||||
|
||||
if err := addColumnsSQLite(db); err != nil {
|
||||
log.Fatalf("添加列失败: %v", err)
|
||||
}
|
||||
|
||||
if err := updateBillingType(db); err != nil {
|
||||
log.Fatalf("更新billing_type失败: %v", err)
|
||||
}
|
||||
|
||||
log.Println("迁移完成!")
|
||||
}
|
||||
|
||||
func columnExists(db *gorm.DB, table, column string) bool {
|
||||
var count int64
|
||||
db.Raw("SELECT COUNT(*) FROM pragma_table_info(?) WHERE name = ?", table, column).Scan(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func addColumnsSQLite(db *gorm.DB) error {
|
||||
log.Println("添加新列...")
|
||||
|
||||
if !columnExists(db, "app_users", "balance") {
|
||||
if err := db.Exec("ALTER TABLE app_users ADD COLUMN balance DECIMAL(10,2) DEFAULT 0").Error; err != nil {
|
||||
return fmt.Errorf("添加app_users.balance列失败: %w", err)
|
||||
}
|
||||
log.Println("添加app_users.balance列成功")
|
||||
} else {
|
||||
log.Println("app_users.balance列已存在")
|
||||
}
|
||||
|
||||
if !columnExists(db, "applications", "deduction_cycle") {
|
||||
if err := db.Exec("ALTER TABLE applications ADD COLUMN deduction_cycle VARCHAR(20) DEFAULT 'per_use'").Error; err != nil {
|
||||
return fmt.Errorf("添加applications.deduction_cycle列失败: %w", err)
|
||||
}
|
||||
log.Println("添加applications.deduction_cycle列成功")
|
||||
} else {
|
||||
log.Println("applications.deduction_cycle列已存在")
|
||||
}
|
||||
|
||||
if !columnExists(db, "applications", "deduction_amount") {
|
||||
if err := db.Exec("ALTER TABLE applications ADD COLUMN deduction_amount DECIMAL(10,2) DEFAULT 1").Error; err != nil {
|
||||
return fmt.Errorf("添加applications.deduction_amount列失败: %w", err)
|
||||
}
|
||||
log.Println("添加applications.deduction_amount列成功")
|
||||
} else {
|
||||
log.Println("applications.deduction_amount列已存在")
|
||||
}
|
||||
|
||||
if !columnExists(db, "applications", "trial_balance") {
|
||||
if err := db.Exec("ALTER TABLE applications ADD COLUMN trial_balance DECIMAL(10,2) DEFAULT 0").Error; err != nil {
|
||||
return fmt.Errorf("添加applications.trial_balance列失败: %w", err)
|
||||
}
|
||||
log.Println("添加applications.trial_balance列成功")
|
||||
} else {
|
||||
log.Println("applications.trial_balance列已存在")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateBillingType(db *gorm.DB) error {
|
||||
log.Println("更新billing_type...")
|
||||
|
||||
result := db.Exec("UPDATE applications SET billing_type = 'count' WHERE billing_type = 'point'")
|
||||
if result.Error != nil {
|
||||
return fmt.Errorf("更新billing_type失败: %w", result.Error)
|
||||
}
|
||||
log.Printf("更新了 %d 个应用的billing_type从point到count", result.RowsAffected)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user