从0到1:x-ui面板集成支付系统实现节点自动化售卖

【免费下载链接】x-ui 支持多协议多用户的 xray 面板 【免费下载链接】x-ui 项目地址: https://gitcode.com/gh_mirrors/xu/x-ui

引言:节点运营的痛点与解决方案

你是否还在为x-ui面板的节点手动开通、流量超限提醒、到期续费等问题烦恼?作为节点服务提供商,当用户量增长到一定规模后,纯人工管理不仅效率低下,还容易出错。本文将详细介绍如何通过第三方支付系统与x-ui面板的深度集成,实现节点服务的自动化售卖与管理,彻底解放你的双手。

读完本文后,你将能够:

  • 理解x-ui面板的数据模型与扩展点
  • 设计支付系统与x-ui的对接方案
  • 实现节点自动开通、流量控制与到期管理
  • 构建完整的用户支付-开通-使用闭环流程

一、x-ui面板数据模型解析

1.1 核心数据结构

x-ui面板的核心数据模型主要定义在database/model/model.go文件中,其中与节点管理相关的主要有User和Inbound两个结构体:

// 用户模型
type User struct {
    Id       int    `json:"id" gorm:"primaryKey;autoIncrement"`
    Username string `json:"username"`
    Password string `json:"password"`
}

// 节点模型
type Inbound struct {
    Id         int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
    UserId     int    `json:"-"`              // 关联用户ID
    Up         int64  `json:"up" form:"up"`   // 上传流量
    Down       int64  `json:"down" form:"down"` // 下载流量
    Total      int64  `json:"total" form:"total"` // 总流量限制
    Remark     string `json:"remark" form:"remark"` // 备注信息
    Enable     bool   `json:"enable" form:"enable"` // 是否启用
    ExpiryTime int64  `json:"expiryTime" form:"expiryTime"` // 到期时间戳
    
    // 配置部分
    Listen         string   `json:"listen" form:"listen"`
    Port           int      `json:"port" form:"port" gorm:"unique"`
    Protocol       Protocol `json:"protocol" form:"protocol"`
    Settings       string   `json:"settings" form:"settings"`
    StreamSettings string   `json:"streamSettings" form:"streamSettings"`
    Tag            string   `json:"tag" form:"tag" gorm:"unique"`
    Sniffing       string   `json:"sniffing" form:"sniffing"`
}

1.2 关键字段分析

对于支付系统集成而言,以下字段尤为重要:

字段名作用支付集成关联性
UserId关联用户ID用于绑定购买用户
Total总流量限制控制不同套餐的流量额度
ExpiryTime到期时间戳实现节点有效期管理
Enable是否启用控制节点开关状态
Up/Down流量统计用于超限检测

1.3 节点服务接口

x-ui提供了InboundService服务类(位于web/service/inbound.go),封装了节点管理的核心操作:

type InboundService struct {}

// 关键方法摘要
func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {}
func (s *InboundService) AddInbound(inbound *model.Inbound) error {}
func (s *InboundService) UpdateInbound(inbound *model.Inbound) error {}
func (s *InboundService) DisableInvalidInbounds() (int64, error) {}

其中DisableInvalidInbounds方法会自动禁用流量超限或已过期的节点,这为支付系统的到期管理提供了天然支持。

二、支付系统集成方案设计

2.1 系统架构设计

支付系统与x-ui的集成可采用以下架构:

mermaid

2.2 数据流程设计

完整的数据流程包含以下步骤:

  1. 用户下单:用户在销售页面选择套餐并完成支付
  2. 支付回调:支付系统向我们的API服务发送支付成功通知
  3. 订单处理:API服务验证回调合法性,解析订单信息
  4. 节点创建:根据套餐信息创建或更新对应的Inbound记录
  5. 配置生效:触发x-ui配置更新,使新节点生效
  6. 通知用户:通过邮件或其他方式将节点信息发送给用户

2.3 数据表扩展设计

为支持支付功能,我们需要扩展以下数据表:

-- 产品套餐表
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL COMMENT '套餐名称',
    description TEXT COMMENT '套餐描述',
    price DECIMAL(10,2) NOT NULL COMMENT '价格',
    traffic_limit BIGINT NOT NULL COMMENT '流量限制(MB)',
    duration_days INT NOT NULL COMMENT '有效期(天)',
    protocol VARCHAR(20) NOT NULL COMMENT '支持协议',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 订单表
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(50) UNIQUE NOT NULL COMMENT '订单编号',
    user_id INT NOT NULL COMMENT '用户ID',
    product_id INT NOT NULL COMMENT '产品ID',
    amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',
    status TINYINT NOT NULL COMMENT '状态:0-待支付,1-已支付,2-已取消',
    payment_time DATETIME COMMENT '支付时间',
    inbound_id INT COMMENT '关联节点ID',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

三、核心功能实现

3.1 支付回调API开发

首先,我们需要在x-ui的web服务中添加支付回调处理接口。创建web/controller/payment.go文件:

package controller

import (
    "net/http"
    "x-ui/database"
    "x-ui/database/model"
    "x-ui/web/service"
    "github.com/gin-gonic/gin"
)

type PaymentController struct {
    inboundService service.InboundService
    // 其他依赖...
}

// 支付回调处理
func (c *PaymentController) HandlePaymentCallback(ctx *gin.Context) {
    // 1. 解析回调参数
    var callbackData PaymentCallbackData
    if err := ctx.ShouldBindJSON(&callbackData); err != nil {
        ctx.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
        return
    }
    
    // 2. 验证签名
    if !verifyPaymentSignature(callbackData) {
        ctx.JSON(http.StatusForbidden, gin.H{"error": "签名验证失败"})
        return
    }
    
    // 3. 查询订单信息
    order := getOrderByNo(callbackData.OrderNo)
    if order == nil || order.Status != 0 {
        ctx.JSON(http.StatusOK, gin.H{"status": "success"}) // 防止重复处理
        return
    }
    
    // 4. 创建/更新节点
    inbound := c.createInboundForOrder(order)
    
    // 5. 更新订单状态
    updateOrderStatus(order.Id, inbound.Id)
    
    ctx.JSON(http.StatusOK, gin.H{"status": "success"})
}

// 根据订单创建节点
func (c *PaymentController) createInboundForOrder(order *Order) *model.Inbound {
    // 获取产品信息
    product := getProductById(order.ProductId)
    
    // 创建节点
    inbound := &model.Inbound{
        UserId:     order.UserId,
        Total:      product.TrafficLimit * 1024 * 1024, // 转换为字节
        Remark:     "Auto-created by payment: " + order.OrderNo,
        Enable:     true,
        ExpiryTime: calculateExpiryTime(product.DurationDays),
        Port:       getAvailablePort(),
        Protocol:   model.Protocol(product.Protocol),
        // 其他必要配置...
    }
    
    // 保存节点
    c.inboundService.AddInbound(inbound)
    
    return inbound
}

3.2 节点自动开通实现

节点开通的核心在于正确设置Inbound结构体并调用x-ui的服务方法:

// 获取可用端口
func getAvailablePort() int {
    // 实现逻辑:查找一个未被占用的端口
    // 可通过查询Inbound表的port字段,找到一个未使用的端口
}

// 计算到期时间戳
func calculateExpiryTime(days int) int64 {
    return time.Now().AddDate(0, 0, days).Unix() * 1000
}

// 更新x-ui配置
func updateXrayConfig() error {
    // 调用x-ui的配置更新逻辑
    xrayService := service.XrayService{}
    return xrayService.Restart()
}

3.3 流量与到期管理

x-ui已内置节点有效性检查机制,我们只需确保正确设置相关字段即可:

// 在InboundService中已存在的方法
func (s *InboundService) DisableInvalidInbounds() (int64, error) {
    db := database.GetDB()
    now := time.Now().Unix() * 1000
    // 禁用流量超限或已过期的节点
    result := db.Model(model.Inbound{}).
        Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true).
        Update("enable", false)
    return result.RowsAffected, result.Error
}

我们可以通过定时任务定期执行此方法,确保及时禁用无效节点:

// 添加到定时任务
func init() {
    // 每小时检查一次
    cron.AddFunc("0 * * * *", func() {
        service.InboundService{}.DisableInvalidInbounds()
    })
}

四、前端界面扩展

4.1 用户中心页面

在x-ui的web界面中添加用户中心页面,展示用户的节点信息和订单历史:

<!-- web/html/xui/user_center.html -->
<div class="user-center">
    <div class="node-list">
        <h2>我的节点</h2>
        <table class="table">
            <thead>
                <tr>
                    <th>节点名称</th>
                    <th>协议</th>
                    <th>端口</th>
                    <th>已用流量</th>
                    <th>剩余流量</th>
                    <th>到期时间</th>
                    <th>状态</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <!-- 动态生成节点列表 -->
                <tr v-for="node in nodes" :key="node.id">
                    <td>{{ node.remark }}</td>
                    <td>{{ node.protocol }}</td>
                    <td>{{ node.port }}</td>
                    <td>{{ formatTraffic(node.up + node.down) }}</td>
                    <td>{{ formatTraffic(node.total - (node.up + node.down)) }}</td>
                    <td>{{ formatTime(node.expiryTime) }}</td>
                    <td :class="node.enable ? 'text-success' : 'text-danger'">
                        {{ node.enable ? '运行中' : '已停用' }}
                    </td>
                    <td>
                        <button @click="showConfig(node)" class="btn btn-sm btn-primary">查看配置</button>
                        <button @click="renewNode(node)" class="btn btn-sm btn-success" v-if="!node.enable">续费</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    
    <div class="order-history">
        <h2>订单历史</h2>
        <!-- 订单列表 -->
    </div>
</div>

4.2 流量统计与可视化

使用Chart.js添加流量统计图表(需引入国内CDN):

<!-- 在页面中添加图表容器 -->
<div class="traffic-chart">
    <canvas id="trafficChart"></canvas>
</div>

<!-- 引入Chart.js (国内CDN) -->
<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>

<script>
// 初始化流量图表
function initTrafficChart(trafficData) {
    const ctx = document.getElementById('trafficChart').getContext('2d');
    new Chart(ctx, {
        type: 'line',
        data: {
            labels: trafficData.dates,
            datasets: [
                {
                    label: '上传流量 (MB)',
                    data: trafficData.upData,
                    borderColor: 'rgb(75, 192, 192)',
                    tension: 0.1
                },
                {
                    label: '下载流量 (MB)',
                    data: trafficData.downData,
                    borderColor: 'rgb(255, 99, 132)',
                    tension: 0.1
                }
            ]
        },
        options: {
            responsive: true,
            scales: {
                y: {
                    beginAtZero: true
                }
            }
        }
    });
}
</script>

五、安全与异常处理

5.1 支付回调安全验证

支付回调必须进行严格的安全验证,防止伪造请求:

// 验证支付签名
func verifyPaymentSignature(data PaymentCallbackData) bool {
    // 1. 按支付平台要求的顺序拼接参数
    params := []string{
        data.MerchantNo,
        data.OrderNo,
        data.Amount,
        // 其他必要参数...
    }
    joined := strings.Join(params, "|")
    
    // 2. 使用商户密钥计算签名
    h := hmac.New(sha256.New, []byte(merchantSecret))
    h.Write([]byte(joined))
    calculatedSign := hex.EncodeToString(h.Sum(nil))
    
    // 3. 与回调数据中的签名比较
    return calculatedSign == data.Signature
}

5.2 并发控制与幂等性处理

为防止重复处理支付回调,需要实现幂等性控制:

// 使用Redis实现分布式锁
func acquireCallbackLock(orderNo string) bool {
    // 尝试获取锁,设置10秒过期
    result, _ := redisClient.SetNX(
        "payment:lock:"+orderNo, 
        "1", 
        10*time.Second,
    ).Result()
    return result
}

// 释放锁
func releaseCallbackLock(orderNo string) {
    redisClient.Del("payment:lock:" + orderNo)
}

// 在回调处理中使用锁
func (c *PaymentController) HandlePaymentCallback(ctx *gin.Context) {
    // ...解析参数
    
    // 获取锁
    if !acquireCallbackLock(callbackData.OrderNo) {
        ctx.JSON(http.StatusOK, gin.H{"status": "success"}) // 已处理,直接返回成功
        return
    }
    defer releaseCallbackLock(callbackData.OrderNo) // 确保释放锁
    
    // ...处理订单
}

5.3 异常情况处理

针对可能出现的异常情况,需要有相应的处理机制:

// 订单处理中的异常捕获
func (c *PaymentController) processOrder(order *Order) {
    defer func() {
        if r := recover(); r != nil {
            // 记录错误日志
            log.Printf("处理订单异常: %v, 订单号: %s", r, order.OrderNo)
            
            // 发送告警通知
            sendAlertEmail("订单处理失败", fmt.Sprintf("订单号: %s, 错误: %v", order.OrderNo, r))
            
            // 可能需要人工干预的订单标记为异常
            markOrderAsException(order.Id)
        }
    }()
    
    // 订单处理逻辑...
}

六、部署与测试

6.1 部署架构

推荐的部署架构如下:

mermaid

6.2 部署步骤

  1. 编译x-ui:

    go build -o x-ui
    
  2. 配置数据库:

    # 导入初始SQL
    mysql -u root -p xui < sql/init.sql
    
  3. 配置支付服务:

    # 修改配置文件
    vi config/payment.json
    
    # 启动服务
    ./payment-service
    
  4. 配置Nginx:

    server {
        listen 443 ssl;
        server_name your.domain.com;
    
        ssl_certificate /path/to/cert.pem;
        ssl_certificate_key /path/to/key.pem;
    
        # 代理x-ui
        location / {
            proxy_pass http://127.0.0.1:54321;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    
        # 代理支付回调
        location /api/payment/callback {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Content-Type application/json;
        }
    }
    

6.3 测试流程

完整的测试流程应包括:

  1. 模拟支付测试:

    # 使用curl模拟支付回调
    curl -X POST https://your.domain.com/api/payment/callback \
         -H "Content-Type: application/json" \
         -d '{"order_no":"TEST123456","amount":"9.90","sign":"xxx..."}'
    
  2. 节点创建验证:

    • 检查数据库中是否创建了对应的Inbound记录
    • 登录x-ui面板查看节点是否正常显示
    • 测试节点是否可以正常连接
  3. 到期禁用测试:

    • 修改测试节点的expiryTime为当前时间之前
    • 执行DisableInvalidInbounds方法
    • 验证节点是否被禁用
  4. 流量超限测试:

    • 修改测试节点的total为较小值
    • 通过工具产生流量使其超限
    • 验证节点是否被禁用

七、总结与扩展

7.1 实现成果总结

通过本文介绍的方案,我们成功实现了x-ui面板与支付系统的集成,主要成果包括:

  1. 设计了完整的支付-开通闭环流程
  2. 实现了节点的自动创建与配置
  3. 开发了基于流量和时间的节点管理机制
  4. 添加了安全的支付回调处理

7.2 后续扩展方向

该集成方案还可以从以下几个方面进行扩展:

  1. 多支付渠道支持:集成更多支付方式,如支付宝、微信支付等
  2. 优惠券系统:添加折扣码、促销活动支持
  3. 多级分销系统:实现推广返佣功能
  4. 用户流量包:支持购买额外流量包
  5. 自动续费功能:实现节点服务的自动续费

7.3 最佳实践建议

在实际运营中,建议:

  1. 定期备份:定期备份x-ui的数据库,防止数据丢失
  2. 监控告警:对支付服务和x-ui服务进行监控,及时发现问题
  3. 流量统计:实现更详细的流量统计和分析,为运营决策提供数据支持
  4. 用户反馈:建立用户反馈渠道,持续优化服务

通过这套方案,你可以将x-ui从一个单纯的节点管理工具,转变为一个功能完善的节点销售平台,实现真正的自动化运营。

如果你觉得本文对你有帮助,请点赞、收藏并关注,下期我们将介绍如何实现x-ui的多语言支持和自定义主题开发。

【免费下载链接】x-ui 支持多协议多用户的 xray 面板 【免费下载链接】x-ui 项目地址: https://gitcode.com/gh_mirrors/xu/x-ui

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐