diff --git a/config.yaml b/config.yaml index d8bf972..ecf6a2c 100644 --- a/config.yaml +++ b/config.yaml @@ -239,3 +239,35 @@ zap: show-line: true log-in-console: true retention-day: -1 + +wechat: + app-id: + app-secret: + token: + aes-key: +pay-list: + - type: wxpay + alias-name: wxpay-1 + app-id: 1 + mch-id: 1 + v3-key: 1 + cert-path: 1 + key-path: 1 + notify-url: 1 + serial-no: 1 + - type: wxpay2 + alias-name: wxpay-2 + app-id: 2 + mch-id: 2 + v3-key: 2 + cert-path: 2 + key-path: 2 + notify-url: 2 + serial-no: 2 + +sms: + access-key-id: your-access-key-id + access-key-secret: your-access-key-secret + sign-name: your-sign-name + template-code: your-template-code + expire-time: 5 \ No newline at end of file diff --git a/config/config.go b/config/config.go index 15da9c7..4f6e458 100644 --- a/config/config.go +++ b/config/config.go @@ -34,4 +34,9 @@ type Server struct { // 跨域配置 Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"` + + // Wechat + Wechat Wechat `mapstructure:"wechat" json:"wechat" yaml:"wechat"` + Pays []Pays `mapstructure:"pay-list" json:"pay-list" yaml:"pay-list"` + SMS SMS `mapstructure:"sms" json:"sms" yaml:"sms"` } diff --git a/config/wechat.go b/config/wechat.go new file mode 100644 index 0000000..107c35f --- /dev/null +++ b/config/wechat.go @@ -0,0 +1,27 @@ +package config + +type Wechat struct { + AppId string `mapstructure:"app-id" json:"app-id" yaml:"app-id"` // 微信小程序appid + AppSecret string `mapstructure:"app-secret" json:"app-secret" yaml:"app-secret"` // 微信小程序appsecret + Token string `mapstructure:"token" json:"token" yaml:"token"` // 微信小程序appsecret + AesKey string `mapstructure:"aes-key" json:"aes-key" yaml:"aes-key"` // 微信小程序appsecret +} + +// Pays 微信支付配置 +// 支持多商户配置 +type Pays struct { + Type string `mapstructure:"type" json:"type" yaml:"type"` + AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"` + Pay `yaml:",inline" mapstructure:",squash"` + Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"` +} + +type Pay struct { + AppId string `mapstructure:"app-id" json:"app-id" yaml:"app-id"` // 微信小程序appid + MchId string `mapstructure:"mch-id" json:"mch-id" yaml:"mch-id"` // 微信小程序appsecret + V3Key string `mapstructure:"v3-key" json:"v3-key" yaml:"v3-key"` // 微信小程序appsecret + CertPath string `mapstructure:"cert-path" json:"cert-path" yaml:"cert-path"` // 微信小程序appsecret + KeyPath string `mapstructure:"key-path" json:"key-path" yaml:"key-path"` // 微信小程序appsecret + NotifyUrl string `mapstructure:"notify-url" json:"notify-url" yaml:"notify-url"` // 微信小程序appsecret + SerialNo string `mapstructure:"serial-no" json:"serial-no" yaml:"serial-no"` // 微信小程序appsecret +} diff --git a/initialize/wechat.go b/initialize/wechat.go new file mode 100644 index 0000000..2b4e6e2 --- /dev/null +++ b/initialize/wechat.go @@ -0,0 +1,72 @@ +package initialize + +import ( + "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel" + "github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount" + "github.com/ArtisanCloud/PowerWeChat/v3/src/payment" + "log" +) + +var WeOfficial *officialAccount.OfficialAccount +var WechatPay *payment.Payment + +// InitWeOfficial 初始化微信公众号 +func InitWeOfficial() { + OfficialAccountApp, err := officialAccount.NewOfficialAccount(&officialAccount.UserConfig{ + AppID: "[appid]", // 公众号、小程序的appid + Secret: "[app secret]", // + + Log: officialAccount.Log{ + Level: "debug", + // 可以重定向到你的目录下,如果设置File和Error,默认会在当前目录下的wechat文件夹下生成日志 + File: "/Users/user/wechat/official-account/info.log", + Error: "/Users/user/wechat/official-account/error.log", + Stdout: false, // 是否打印在终端 + }, + + HttpDebug: true, + Debug: false, + }) + + if err != nil { + log.Println("初始化微信公众号 SDK失败", err) + } + WeOfficial = OfficialAccountApp +} + +// InitWechatPay 初始化微信支付 +func InitWechatPay() { + PaymentService, err := payment.NewPayment(&payment.UserConfig{ + AppID: "[app_id]", // 小程序、公众号或者企业微信的appid + MchID: "[mch_id]", // 商户号 appID + MchApiV3Key: "[mch_api_v3_key]", // 微信V3接口调用必填 + Key: "[key]", // 微信V2接口调用必填 + CertPath: "[wx_cert_path]", // 商户后台支付的Cert证书路径 + KeyPath: "[wx_key_path]", // 商户后台支付的Key证书路径 + SerialNo: "[serial_no]", // 商户支付证书序列号 + NotifyURL: "[notify_url]", // 微信支付回调地址 + HttpDebug: true, + Log: payment.Log{ + Level: "debug", + // 可以重定向到你的目录下,如果设置File和Error,默认会在当前目录下的wechat文件夹下生成日志 + File: "/Users/user/wechat/payment/info.log", + Error: "/Users/user/wechat/payment/error.log", + Stdout: false, // 是否打印在终端 + }, + Http: payment.Http{ + Timeout: 30.0, + BaseURI: "https://api.mch.weixin.qq.com", + }, + // 可选,不传默认走程序内存 + Cache: kernel.NewRedisClient(&kernel.UniversalOptions{ + Addrs: []string{"127.0.0.1:6379"}, + Password: "", + DB: 0, + }), + }) + + if err != nil { + log.Println("初始化微信支付 SDK失败", err) + } + WechatPay = PaymentService +} diff --git a/utils/sms/sms.go b/utils/sms/sms.go index da5cfbb..cb6aa66 100644 --- a/utils/sms/sms.go +++ b/utils/sms/sms.go @@ -4,9 +4,13 @@ package sms import ( "encoding/json" "git.echol.cn/loser/lckt/global" + "github.com/alibabacloud-go/tea/tea" "go.uber.org/zap" - smsApi "github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi" + util "github.com/alibabacloud-go/tea-utils/v2/service" + + openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" + dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v4/client" ) type message struct { @@ -14,29 +18,56 @@ type message struct { } func SendSMS(phone string, code string) bool { - var err error - smsConfig := global.GVA_CONFIG.SMS - client, err := smsApi.NewClientWithAccessKey("cn-qingdao", smsConfig.AccessKeyID, smsConfig.AccessKeySecret) + // 从配置中获取阿里云短信配置 + aliyunConfig := global.GVA_CONFIG.SMS + + clientConfig := &openapi.Config{ + AccessKeyId: tea.String(aliyunConfig.AccessKeyID), + AccessKeySecret: tea.String(aliyunConfig.AccessKeySecret), + Endpoint: tea.String("dysmsapi.aliyuncs.com"), + RegionId: tea.String("cn-hangzhou"), // 添加区域配置 + } + + smsClient, err := dysmsapi.NewClient(clientConfig) if err != nil { - global.GVA_LOG.Error("创建短信服务连接失败", zap.Error(err)) + global.GVA_LOG.Error("创建短信客户端失败", zap.Error(err)) + return false + } + mes := message{Code: code} + templateParam, err := json.Marshal(mes) + if err != nil { + global.GVA_LOG.Error("模板参数序列化失败", zap.Error(err)) return false } - mes := message{Code: code} - param, err := json.Marshal(mes) + sendSmsRequest := &dysmsapi.SendSmsRequest{ + PhoneNumbers: tea.String(phone), + SignName: tea.String(aliyunConfig.SignName), + TemplateCode: tea.String(aliyunConfig.TemplateCode), + TemplateParam: tea.String(string(templateParam)), + } - request := smsApi.CreateSendSmsRequest() - request.Scheme = "https" - request.PhoneNumbers = phone //接收短信的手机号码 - request.SignName = smsConfig.SignName //短信签名名称 - request.TemplateCode = smsConfig.TemplateCode //短信模板ID - request.TemplateParam = string(param) + // 添加更多的运行时选项 + runtime := &util.RuntimeOptions{ + ReadTimeout: tea.Int(5000), + ConnectTimeout: tea.Int(5000), + } - response, err := client.SendSms(request) - if err != nil || response.Message != "OK" { + response, err := smsClient.SendSmsWithOptions(sendSmsRequest, runtime) + if err != nil { global.GVA_LOG.Error("发送短信失败", zap.Error(err)) return false } + if response.Body == nil || *response.Body.Code != "OK" { + if response.Body != nil { + global.GVA_LOG.Error("服务商返回错误", zap.Any("resp", *response.Body.Message)) + } else { + global.GVA_LOG.Error("服务商返回错误", zap.String("resp", "response body is nil")) + } + return false + } + + global.GVA_LOG.Info("短信[阿里云]", zap.String("发送成功", "手机号: "+phone)) return true }