package payment import ( "context" "crypto/rsa" "fmt" "log" "strings" "time" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/auth" "github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers" "github.com/wechatpay-apiv3/wechatpay-go/core/downloader" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi" "github.com/wechatpay-apiv3/wechatpay-go/utils" "dd_fiber_api/config" ) // min 返回两个整数中的较小值 func min(a, b int) int { if a < b { return a } return b } // WechatPayV3Service 微信支付V3服务(使用官方SDK) type WechatPayV3Service struct { config *config.WechatConfig client *core.Client // 官方SDK客户端 privateKey *rsa.PrivateKey // 保存私钥,用于生成支付签名 } // NewWechatPayV3Service 创建微信支付V3服务实例(使用官方SDK) func NewWechatPayV3Service(cfg *config.WechatConfig) (*WechatPayV3Service, error) { // 加载私钥 var privateKey *rsa.PrivateKey var err error // 优先使用私钥内容,其次使用文件路径 if cfg.PrivateKey != "" { // 从字符串加载私钥 privateKey, err = utils.LoadPrivateKey(cfg.PrivateKey) if err != nil { return nil, fmt.Errorf("加载私钥失败: %v", err) } } else if cfg.PrivateKeyPath != "" { // 从文件路径加载私钥 privateKey, err = utils.LoadPrivateKeyWithPath(cfg.PrivateKeyPath) if err != nil { return nil, fmt.Errorf("加载私钥文件失败: %v", err) } } else { return nil, fmt.Errorf("未配置私钥,请设置 private_key 或 private_key_path") } // 使用官方SDK初始化客户端 ctx := context.Background() // 验证配置参数 apiKeyV3 := strings.TrimSpace(cfg.APIKeyV3) if apiKeyV3 == "" { return nil, fmt.Errorf("API Key V3 不能为空") } if len(apiKeyV3) < 32 { log.Printf("⚠️ 警告: API Key V3 长度异常(%d 字符),请确认配置正确", len(apiKeyV3)) } if cfg.MchID == "" { return nil, fmt.Errorf("商户号(mch_id)不能为空") } if cfg.SerialNo == "" { return nil, fmt.Errorf("证书序列号(serial_no)不能为空") } log.Printf(" 正在初始化微信支付客户端: 商户号=%s, 证书序列号=%s, API Key V3长度=%d", cfg.MchID, cfg.SerialNo, len(apiKeyV3)) opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher( cfg.MchID, cfg.SerialNo, privateKey, apiKeyV3, ), } client, err := core.NewClient(ctx, opts...) if err != nil { // 提供更详细的错误信息 errMsg := fmt.Sprintf("初始化微信支付客户端失败: %v", err) if strings.Contains(err.Error(), "decrypt") || strings.Contains(err.Error(), "cipher") { errMsg += "\n可能的原因:" errMsg += "\n1. API Key V3 配置错误(请检查微信商户平台中的 API v3 密钥)" errMsg += "\n2. 证书序列号(serial_no)不正确" errMsg += "\n3. 私钥文件与证书序列号不匹配" errMsg += "\n4. 商户号(mch_id)配置错误" errMsg += fmt.Sprintf("\n当前配置: mch_id=%s, serial_no=%s, api_key_v3长度=%d", cfg.MchID, cfg.SerialNo, len(apiKeyV3)) } return nil, fmt.Errorf(errMsg) } log.Println(" ✅ 微信支付 V3 客户端初始化成功(使用官方SDK)") // 由于WithWechatPayAutoAuthCipher已经配置了自动证书更新,我们需要获取证书管理器 // 但是client没有公开方法获取,我们需要通过其他方式 // 实际上,我们可以创建一个新的证书管理器,或者使用client的内部方法 // 这里我们先尝试使用client作为CertificateGetter(如果它实现了接口) // 如果不行,我们需要手动创建证书管理器 // 暂时先不设置certificateGetter,在GetVerifier中处理 service := &WechatPayV3Service{ config: cfg, client: client, privateKey: privateKey, // 保存私钥用于生成支付签名 } // 尝试从client获取证书管理器(如果client实现了CertificateGetter接口) // 由于client没有公开方法,我们需要使用反射或其他方式 // 或者,我们可以创建一个新的证书管理器 // 这里我们先返回service,在GetVerifier中处理 return service, nil } // CreateWechatPayV3Request 创建微信支付V3订单请求 type CreateWechatPayV3Request struct { OrderID string `json:"order_id"` // 关联的订单ID(雪花ID,字符串格式) Description string `json:"description"` // 商品描述 OpenID string `json:"openid"` // 用户openid(小程序支付必需) Amount int32 `json:"amount"` // 支付金额(分) } // CreateWechatPayV3Response 创建微信支付V3订单响应 type CreateWechatPayV3Response struct { OrderID string `json:"order_id"` // 关联的订单ID PrepayID string `json:"prepay_id"` // 预支付交易会话标识 AppID string `json:"app_id"` // 微信应用ID TimeStamp string `json:"time_stamp"` // 时间戳 NonceStr string `json:"nonce_str"` // 随机字符串 Package string `json:"package"` // 订单详情扩展字符串(prepay_id=xxx) SignType string `json:"sign_type"` // 签名方式(RSA) PaySign string `json:"pay_sign"` // 签名 Success bool `json:"success"` // 是否成功 Message string `json:"message"` // 响应消息 } // CreateWechatPayV3 创建微信支付V3订单(使用官方SDK) func (s *WechatPayV3Service) CreateWechatPayV3(ctx context.Context, req *CreateWechatPayV3Request) (*CreateWechatPayV3Response, error) { // 验证 openid(小程序支付必需) if req.OpenID == "" { return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: "openid 是必需的(小程序支付)", }, nil } // 验证金额 if req.Amount <= 0 { return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: "支付金额必须大于0", }, nil } // 使用官方SDK创建小程序支付订单 svc := jsapi.JsapiApiService{Client: s.client} request := jsapi.PrepayRequest{ Appid: core.String(s.config.AppID), Mchid: core.String(s.config.MchID), Description: core.String(req.Description), OutTradeNo: core.String(req.OrderID), NotifyUrl: core.String(s.config.NotifyURL), Amount: &jsapi.Amount{ Total: core.Int64(int64(req.Amount)), Currency: core.String("CNY"), }, Payer: &jsapi.Payer{ Openid: core.String(req.OpenID), }, } // 调用官方SDK创建订单 resp, result, err := svc.Prepay(ctx, request) if err != nil { log.Printf("⚠️ 创建微信支付订单失败: %v", err) return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: fmt.Sprintf("创建支付订单失败: %v", err), }, nil } // 检查HTTP响应状态码(从result中获取) if result != nil && result.Response != nil && result.Response.StatusCode != 200 { log.Printf("⚠️ 微信支付返回错误状态码: %d", result.Response.StatusCode) return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: fmt.Sprintf("微信支付返回错误: HTTP %d", result.Response.StatusCode), }, nil } // 获取 prepay_id(从resp中获取) prepayID := "" if resp != nil && resp.PrepayId != nil { prepayID = *resp.PrepayId } if prepayID == "" { return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: "微信支付返回缺少 prepay_id", }, nil } log.Printf("✅ 创建微信支付订单成功: prepay_id=%s", prepayID) // 生成小程序支付所需的签名参数 timestamp := time.Now().Unix() nonceStr, err := utils.GenerateNonce() if err != nil { return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: fmt.Sprintf("生成随机字符串失败: %v", err), }, nil } packageStr := fmt.Sprintf("prepay_id=%s", prepayID) // 使用官方SDK生成支付签名 signStr := fmt.Sprintf("%s\n%d\n%s\n%s\n", s.config.AppID, timestamp, nonceStr, packageStr) signature, err := utils.SignSHA256WithRSA(signStr, s.privateKey) if err != nil { return &CreateWechatPayV3Response{ OrderID: req.OrderID, Success: false, Message: fmt.Sprintf("生成支付签名失败: %v", err), }, nil } // 构造返回结果 resultResp := &CreateWechatPayV3Response{ OrderID: req.OrderID, PrepayID: prepayID, AppID: s.config.AppID, TimeStamp: fmt.Sprintf("%d", timestamp), NonceStr: nonceStr, Package: packageStr, SignType: "RSA", PaySign: signature, Success: true, Message: "创建支付订单成功", } return resultResp, nil } // GetClient 获取官方SDK客户端(用于notify handler) func (s *WechatPayV3Service) GetClient() *core.Client { return s.client } // GetAPIKeyV3 获取APIv3密钥(用于notify handler) func (s *WechatPayV3Service) GetAPIKeyV3() string { return strings.TrimSpace(s.config.APIKeyV3) } // GetVerifier 获取验证器(用于notify handler) // 直接使用官方SDK的downloader管理器获取证书访问器 // 这与WithWechatPayAutoAuthCipher使用的机制相同,是官方推荐的方式 func (s *WechatPayV3Service) GetVerifier() (auth.Verifier, error) { // 使用官方SDK的downloader管理器获取证书访问器 mgr := downloader.MgrInstance() certGetter := mgr.GetCertificateVisitor(s.config.MchID) if certGetter == nil { return nil, fmt.Errorf("无法从downloader获取证书访问器,商户号: %s", s.config.MchID) } // 使用证书管理器创建verifier verifier := verifiers.NewSHA256WithRSAVerifier(certGetter) return verifier, nil }