HaniBlindBox/docs/API迁移详细文档/阶段6-支付集成.md
2026-01-02 01:00:52 +08:00

15 KiB
Raw Blame History

阶段6支付集成

阶段概述

时间: 2周
目标: 实现完整的支付系统,包括微信支付、余额支付、积分支付等多种支付方式
优先级: P1 (高优先级)

详细任务清单

6.1 微信支付集成 (5天)

任务描述

集成微信支付SDK实现微信小程序支付和H5支付

具体工作

  • 集成微信支付SDK
  • 实现统一下单接口
  • 实现支付参数签名
  • 实现支付回调处理
  • 实现支付状态查询
  • 实现退款功能

核心接口实现

创建微信支付订单接口
POST /api/v1/payment/wechat/create
Authorization: Bearer {token}
Content-Type: application/json

Request:
{
  "order_no": "ORD202401010001",
  "amount": "10.00",
  "description": "商品购买",
  "openid": "oABC123456789",
  "client_ip": "192.168.1.1"
}

Response:
{
  "status": 1,
  "msg": "支付订单创建成功",
  "data": {
    "appId": "wx1234567890abcdef",
    "timeStamp": "1704067200",
    "nonceStr": "abc123def456",
    "package": "prepay_id=wx123456789012345",
    "signType": "RSA",
    "paySign": "signature_string_here"
  }
}
微信支付回调接口
POST /api/v1/payment/wechat/notify
Content-Type: application/json

Request:
{
  "id": "notification_id",
  "create_time": "2024-01-01T12:00:00+08:00",
  "event_type": "TRANSACTION.SUCCESS",
  "resource_type": "encrypt-resource",
  "resource": {
    "original_type": "transaction",
    "algorithm": "AEAD_AES_256_GCM",
    "ciphertext": "encrypted_data",
    "associated_data": "transaction",
    "nonce": "nonce_string"
  }
}

Response:
{
  "code": "SUCCESS",
  "message": "成功"
}

技术实现要点

// 微信支付服务接口
public interface IWechatPayService
{
    Task<WechatPayResult> CreatePaymentAsync(WechatPayRequest request);
    Task<bool> HandleNotifyAsync(WechatPayNotify notify);
    Task<PaymentQueryResult> QueryPaymentAsync(string orderNo);
    Task<RefundResult> RefundAsync(RefundRequest request);
}

// 微信支付配置
public class WechatPayConfig
{
    public string AppId { get; set; }
    public string MchId { get; set; }
    public string ApiKey { get; set; }
    public string CertPath { get; set; }
    public string NotifyUrl { get; set; }
    public string RefundNotifyUrl { get; set; }
}

// 微信支付服务实现
public class WechatPayService : IWechatPayService
{
    public async Task<WechatPayResult> CreatePaymentAsync(WechatPayRequest request)
    {
        // 1. 构建统一下单请求
        var unifiedOrderRequest = new UnifiedOrderRequest
        {
            AppId = _config.AppId,
            MchId = _config.MchId,
            Body = request.Description,
            OutTradeNo = request.OrderNo,
            TotalFee = (int)(request.Amount * 100), // 转换为分
            SpbillCreateIp = request.ClientIp,
            NotifyUrl = _config.NotifyUrl,
            TradeType = "JSAPI",
            OpenId = request.OpenId
        };
        
        // 2. 签名
        unifiedOrderRequest.Sign = GenerateSign(unifiedOrderRequest);
        
        // 3. 调用微信API
        var response = await CallWechatApiAsync(unifiedOrderRequest);
        
        // 4. 生成支付参数
        return new WechatPayResult
        {
            AppId = response.AppId,
            TimeStamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(),
            NonceStr = GenerateNonceStr(),
            Package = $"prepay_id={response.PrepayId}",
            SignType = "MD5",
            PaySign = GeneratePaySign(/* parameters */)
        };
    }
    
    public async Task<bool> HandleNotifyAsync(WechatPayNotify notify)
    {
        // 1. 验证签名
        if (!VerifyNotifySign(notify))
        {
            return false;
        }
        
        // 2. 解密数据
        var paymentData = DecryptNotifyData(notify.Resource);
        
        // 3. 更新订单状态
        await _orderService.UpdatePaymentStatusAsync(
            paymentData.OutTradeNo, 
            paymentData.TransactionId,
            PaymentStatus.Success
        );
        
        return true;
    }
}

6.2 余额支付系统 (3天)

任务描述

实现用户余额支付功能

具体工作

  • 实现余额支付接口
  • 实现余额扣减逻辑
  • 实现支付密码验证
  • 实现余额不足处理
  • 实现支付记录

核心接口实现

余额支付接口
POST /api/v1/payment/balance/pay
Authorization: Bearer {token}
Content-Type: application/json

Request:
{
  "order_no": "ORD202401010001",
  "amount": "10.00",
  "pay_password": "123456"
}

Response:
{
  "status": 1,
  "msg": "支付成功",
  "data": {
    "pay_no": "BAL202401010001",
    "pay_time": "2024-01-01T12:00:00Z",
    "remaining_balance": "90.00"
  }
}
设置支付密码接口
POST /api/v1/user/payment-password
Authorization: Bearer {token}
Content-Type: application/json

Request:
{
  "password": "123456",
  "confirm_password": "123456",
  "sms_code": "123456"
}

Response:
{
  "status": 1,
  "msg": "支付密码设置成功"
}

技术实现要点

// 余额支付服务
public interface IBalancePayService
{
    Task<BalancePayResult> PayAsync(BalancePayRequest request);
    Task<bool> VerifyPayPasswordAsync(int userId, string password);
    Task<bool> SetPayPasswordAsync(int userId, string password, string smsCode);
}

public class BalancePayService : IBalancePayService
{
    public async Task<BalancePayResult> PayAsync(BalancePayRequest request)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        try
        {
            // 1. 验证支付密码
            if (!await VerifyPayPasswordAsync(request.UserId, request.PayPassword))
            {
                throw new BusinessException("支付密码错误");
            }
            
            // 2. 检查余额
            var user = await _context.Users.FindAsync(request.UserId);
            if (user.Money < request.Amount)
            {
                throw new BusinessException("余额不足");
            }
            
            // 3. 扣减余额
            user.Money -= request.Amount;
            
            // 4. 记录支付记录
            var payRecord = new ProfitPay
            {
                UserId = request.UserId,
                ChangeMoney = -request.Amount,
                Content = "余额支付",
                OrderNo = request.OrderNo,
                PayType = (int)PayType.Balance,
                AddTime = DateTime.Now
            };
            _context.ProfitPays.Add(payRecord);
            
            // 5. 更新订单状态
            await _orderService.UpdatePaymentStatusAsync(
                request.OrderNo, 
                payRecord.Id.ToString(),
                PaymentStatus.Success
            );
            
            await _context.SaveChangesAsync();
            await transaction.CommitAsync();
            
            return new BalancePayResult
            {
                PayNo = payRecord.Id.ToString(),
                PayTime = payRecord.AddTime,
                RemainingBalance = user.Money
            };
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
}

6.3 积分支付系统 (2天)

任务描述

实现积分支付功能

具体工作

  • 实现积分支付接口
  • 实现积分扣减逻辑
  • 实现积分兑换比例配置
  • 实现积分不足处理

核心接口实现

积分支付接口
POST /api/v1/payment/integral/pay
Authorization: Bearer {token}
Content-Type: application/json

Request:
{
  "order_no": "ORD202401010001",
  "integral_amount": "100.00",
  "money_amount": "10.00"
}

Response:
{
  "status": 1,
  "msg": "积分支付成功",
  "data": {
    "pay_no": "INT202401010001",
    "pay_time": "2024-01-01T12:00:00Z",
    "remaining_integral": "900.00"
  }
}

6.4 混合支付系统 (2天)

任务描述

实现多种支付方式的混合支付

具体工作

  • 实现混合支付接口
  • 实现支付方式优先级
  • 实现支付金额分配
  • 实现混合支付回滚

核心接口实现

混合支付接口
POST /api/v1/payment/mixed/pay
Authorization: Bearer {token}
Content-Type: application/json

Request:
{
  "order_no": "ORD202401010001",
  "total_amount": "30.00",
  "payment_methods": [
    {
      "type": "balance",
      "amount": "10.00"
    },
    {
      "type": "integral", 
      "amount": "100.00",
      "money_equivalent": "10.00"
    },
    {
      "type": "wechat",
      "amount": "10.00"
    }
  ]
}

Response:
{
  "status": 1,
  "msg": "混合支付创建成功",
  "data": {
    "balance_paid": "10.00",
    "integral_paid": "100.00",
    "wechat_pay_info": {
      "appId": "wx1234567890abcdef",
      "timeStamp": "1704067200",
      "nonceStr": "abc123def456",
      "package": "prepay_id=wx123456789012345",
      "signType": "RSA",
      "paySign": "signature_string_here"
    }
  }
}

6.5 支付状态管理 (2天)

任务描述

实现支付状态的统一管理和查询

具体工作

  • 实现支付状态查询接口
  • 实现支付状态同步
  • 实现支付失败处理
  • 实现支付超时处理

核心接口实现

支付状态查询接口
GET /api/v1/payment/{orderNo}/status
Authorization: Bearer {token}

Response:
{
  "status": 1,
  "msg": "请求成功",
  "data": {
    "order_no": "ORD202401010001",
    "pay_status": "SUCCESS",
    "pay_type": "WECHAT",
    "pay_amount": "10.00",
    "pay_time": "2024-01-01T12:00:00Z",
    "pay_no": "wx123456789012345",
    "payment_details": [
      {
        "method": "balance",
        "amount": "5.00",
        "status": "SUCCESS"
      },
      {
        "method": "wechat",
        "amount": "5.00", 
        "status": "SUCCESS"
      }
    ]
  }
}
支付重试接口
POST /api/v1/payment/{orderNo}/retry
Authorization: Bearer {token}

Response:
{
  "status": 1,
  "msg": "支付重试成功",
  "data": {
    "new_pay_info": {
      // 新的支付参数
    }
  }
}

支付安全机制

签名验证

public class PaymentSecurityService
{
    // 生成签名
    public string GenerateSign(Dictionary<string, string> parameters, string key)
    {
        var sortedParams = parameters
            .Where(p => !string.IsNullOrEmpty(p.Value) && p.Key != "sign")
            .OrderBy(p => p.Key)
            .Select(p => $"{p.Key}={p.Value}")
            .ToList();
        
        var stringToSign = string.Join("&", sortedParams) + "&key=" + key;
        return MD5Hash(stringToSign).ToUpper();
    }
    
    // 验证签名
    public bool VerifySign(Dictionary<string, string> parameters, string key, string sign)
    {
        var calculatedSign = GenerateSign(parameters, key);
        return calculatedSign.Equals(sign, StringComparison.OrdinalIgnoreCase);
    }
    
    // 防重放攻击
    public async Task<bool> CheckNonceAsync(string nonce, TimeSpan expiry)
    {
        var key = $"payment_nonce:{nonce}";
        var exists = await _redis.ExistsAsync(key);
        
        if (exists)
        {
            return false; // 重复请求
        }
        
        await _redis.SetAsync(key, "1", expiry);
        return true;
    }
}

支付密码加密

public class PaymentPasswordService
{
    public string HashPassword(string password, string salt)
    {
        return BCrypt.Net.BCrypt.HashPassword(password + salt);
    }
    
    public bool VerifyPassword(string password, string salt, string hash)
    {
        return BCrypt.Net.BCrypt.Verify(password + salt, hash);
    }
    
    public async Task<bool> CheckPayPasswordAttemptsAsync(int userId)
    {
        var key = $"pay_password_attempts:{userId}";
        var attempts = await _redis.GetAsync<int>(key);
        
        if (attempts >= 5)
        {
            return false; // 超过最大尝试次数
        }
        
        return true;
    }
}

支付数据模型

支付记录表

public class PaymentRecord
{
    public int Id { get; set; }
    public string PayNo { get; set; }
    public string OrderNo { get; set; }
    public int UserId { get; set; }
    public int PayType { get; set; }
    public decimal Amount { get; set; }
    public int Status { get; set; }
    public string ThirdPartyNo { get; set; }
    public string NotifyData { get; set; }
    public DateTime CreateTime { get; set; }
    public DateTime? PayTime { get; set; }
    public DateTime? NotifyTime { get; set; }
}

public class PaymentMethod
{
    public int Id { get; set; }
    public string PayNo { get; set; }
    public int MethodType { get; set; }
    public decimal Amount { get; set; }
    public int Status { get; set; }
    public string MethodData { get; set; }
    public DateTime CreateTime { get; set; }
}

支付配置管理

支付方式配置

public class PaymentConfig
{
    public class WechatPay
    {
        public bool Enabled { get; set; } = true;
        public decimal MinAmount { get; set; } = 0.01m;
        public decimal MaxAmount { get; set; } = 50000m;
        public string AppId { get; set; }
        public string MchId { get; set; }
        public string ApiKey { get; set; }
    }
    
    public class BalancePay
    {
        public bool Enabled { get; set; } = true;
        public decimal MinAmount { get; set; } = 0.01m;
        public bool RequirePassword { get; set; } = true;
        public int MaxDailyAmount { get; set; } = 10000;
    }
    
    public class IntegralPay
    {
        public bool Enabled { get; set; } = true;
        public decimal ExchangeRate { get; set; } = 10m; // 10积分=1元
        public decimal MinIntegral { get; set; } = 10m;
        public decimal MaxIntegralPerOrder { get; set; } = 1000m;
    }
}

验收标准

功能验收

  • 微信支付流程完整可用
  • 余额支付功能正常
  • 积分支付功能正常
  • 混合支付功能正常
  • 支付状态管理正确
  • 支付安全机制有效

性能验收

  • 支付创建接口响应时间 < 1000ms
  • 支付回调处理时间 < 500ms
  • 支付状态查询响应时间 < 200ms
  • 支持并发支付 > 100 QPS

安全验收

  • 签名验证机制正确
  • 支付密码加密安全
  • 防重放攻击有效
  • 支付数据传输安全

准确性验收

  • 支付金额计算准确率 100%
  • 支付状态同步准确率 100%
  • 资产扣减准确率 100%
  • 支付记录完整性 100%

风险点和注意事项

技术风险

  1. 支付安全: 支付接口的安全性和防篡改
  2. 网络异常: 支付过程中的网络中断处理
  3. 数据一致性: 支付状态和订单状态的一致性
  4. 并发控制: 高并发支付时的数据安全

解决方案

  1. 多重验证: 签名验证、时间戳验证、随机数验证
  2. 重试机制: 支付失败时的自动重试
  3. 事务管理: 严格的事务控制确保数据一致性
  4. 分布式锁: 关键支付操作使用分布式锁

下一阶段准备

为阶段7准备的内容

  • 抽奖算法基础
  • 概率计算引擎
  • 随机数生成器
  • 奖品发放机制

交接文档

  • 支付系统架构说明
  • 微信支付集成指南
  • 支付安全机制文档
  • 支付配置管理手册

阶段6完成标志: 支付系统功能完整,包括微信支付、余额支付、积分支付等功能正常运行,支付安全性和准确性得到保障。