diff --git a/cmd/app.go b/cmd/app.go index 024493f..54b8331 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -18,25 +18,29 @@ package main import ( + "fmt" + "dubbo.apache.org/dubbo-go/v3/common/logger" "dubbo.apache.org/dubbo-go/v3/config" _ "dubbo.apache.org/dubbo-go/v3/imports" - "fmt" appconfig "github.com/fonchain_enterprise/micro-account/cmd/config" msgconfig "github.com/fonchain_enterprise/micro-account/pkg/config" "github.com/fonchain_enterprise/micro-account/pkg/cache" "github.com/fonchain_enterprise/micro-account/pkg/common/dingding" _ "github.com/fonchain_enterprise/micro-account/pkg/common/filter" + "github.com/fonchain_enterprise/micro-account/pkg/common/verifica" + + "os" "github.com/fonchain_enterprise/micro-account/pkg/m" "github.com/fonchain_enterprise/micro-account/pkg/model" + "github.com/fonchain_enterprise/micro-account/pkg/model/message" "github.com/fonchain_enterprise/micro-account/pkg/service" "github.com/fonchain_enterprise/utils/zap_log" "github.com/nacos-group/nacos-sdk-go/clients" "github.com/nacos-group/nacos-sdk-go/common/constant" "github.com/nacos-group/nacos-sdk-go/vo" - "os" ) func main() { @@ -101,6 +105,18 @@ func bootstrap() (err error) { } model.LoadEnv(mysqlConfig) + verifica.SetHuYiTemplateResolver(func(templateId uint) (uint, bool) { + var templateEntity *message.TemplateMessageEntity + model.DB.Model(&message.TemplateMessageEntity{}). + Where(&message.TemplateMessageEntity{TemplateId: templateId}). + First(&templateEntity) + + if templateEntity == nil || templateEntity.HuYiTemplateId == 0 { + return 0, false + } + + return templateEntity.HuYiTemplateId, true + }) //redis redisConfig := cache.RedisConfig{ diff --git a/pkg/application/msg/msg.go b/pkg/application/msg/msg.go new file mode 100644 index 0000000..8068836 --- /dev/null +++ b/pkg/application/msg/msg.go @@ -0,0 +1,116 @@ +package msg + +import ( + "bytes" + "crypto/sha1" + "encoding/json" + "fmt" + "io" + "math/rand" + "net/http" + "sort" + "strings" + "time" + + "dubbo.apache.org/dubbo-go/v3/common/logger" +) + +const ( + ClientID = "fenglian" + SECRET = "93a8894116ce0152dd5e145370fc83aa" +) + +type SendReport struct { + MsgNo string `json:"msgNo"` + TempNo string `json:"tempNo"` + SigNo string `json:"signNo"` + Content string `json:"content"` + SendTime string `json:"sendTime"` + Mobile string `json:"mobile"` + SendFrom string `json:"sendFrom"` +} + +type SendMsgResponse struct { + Code int `json:"code"` // 对应 JSON 中的 "code" 字段(整数) + Msg string `json:"msg"` // 对应 JSON 中的 "msg" 字段(字符串) + MsgNo string `json:"msg_no"` // 对应 JSON 中的 "msg_no" 字段(字符串) + Count int `json:"count"` // 对应 JSON 中的 "count" 字段(整数) +} + +// 6位随机验证码 +func RandCode() string { + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + rndCode := fmt.Sprintf("%06v", rnd.Int31n(1000000)) + fmt.Println(rndCode) + return rndCode +} + +func ReportMsgWithSendFrom(res SendMsgResponse, telNum string, tempNo uint, sigNo uint, content string, sendFrom string) { + + //发送成功,上报发送信息 + reqObj := SendReport{ + MsgNo: res.MsgNo, + TempNo: fmt.Sprintf("%d", tempNo), + SigNo: fmt.Sprintf("%d", sigNo), + Content: content, + Mobile: telNum, + SendTime: time.Now().Format("2006-01-02 15:04:05"), + SendFrom: sendFrom, + } + + jsonData, err := json.Marshal(reqObj) + if err != nil { + return + } + + // 构造 POST 请求 + non := RandCode() + timeNow := fmt.Sprintf("%d", time.Now().Unix()) + sign, _ := makeSignature(SECRET, timeNow, non, ClientID) + url := fmt.Sprintf("https://common.szjixun.cn/api/msg/report?client=%s&nonce=%s×tamp=%s&sign=%s", ClientID, non, timeNow, sign) // 这里的SECRET需要替换为实际的密钥 + fmt.Println("url", url) + + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData)) + if err != nil { + return + } + req.Header.Set("Content-Type", "application/json") + + // 发送请求 + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + logger.Fatalf("发送请求失败: %v", err) + return + } + + defer resp.Body.Close() + + // 检查状态码 + if resp.StatusCode != http.StatusOK { + errBody, _ := io.ReadAll(resp.Body) + logger.Fatalf("请求失败,状态码: %d,响应: %s", resp.StatusCode, string(errBody)) + return + } + + // 读取并反序列化响应 + respBody, err := io.ReadAll(resp.Body) + + fmt.Println(string(respBody)) + + return + +} + +func makeSignature(secret string, timestamp string, nonce string, client string) (ret string, err error) { + strs := []string{secret, timestamp, nonce, client} + fmt.Println(timestamp) + fmt.Println(nonce) + + sort.Strings(strs) + vv := strings.Join(strs, "") + t := sha1.New() + t.Write([]byte(vv)) + + return fmt.Sprintf("%x", t.Sum(nil)), nil +} diff --git a/pkg/common/verifica/mobile.go b/pkg/common/verifica/mobile.go index d4d7447..0009519 100644 --- a/pkg/common/verifica/mobile.go +++ b/pkg/common/verifica/mobile.go @@ -1,8 +1,15 @@ package verifica import ( + "bytes" + "encoding/json" "errors" "fmt" + "io" + "net/http" + "net/url" + + "github.com/fonchain_enterprise/micro-account/pkg/application/msg" "github.com/fonchain_enterprise/micro-account/pkg/config" "github.com/fonchain_enterprise/utils/mobile" ) @@ -12,6 +19,13 @@ import ( const SIG_NO = 145031 const SIG_NO_SELLER = 159789 +var huYiTemplateResolver func(templateId uint) (huYiTemplateId uint, ok bool) + +// SetHuYiTemplateResolver injects how template overrides are loaded. +func SetHuYiTemplateResolver(resolver func(templateId uint) (huYiTemplateId uint, ok bool)) { + huYiTemplateResolver = resolver +} + func SendMsg(telNum string, project string) (string, error) { TMP := 277455 var sigNo uint @@ -127,10 +141,34 @@ func SendCustomCode(telNum string, templateId uint, sigNo uint) (string, error) fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code) //fmt.Println("发送短信请求参数:", telNum, mobile.Sign, mobile.AlTMP1, code) + //临时修改下 + isHuYi, templateId := codeIsUseHuLian(templateId) + + fmt.Println("定制化发送短信:", isHuYi, templateId) + if isHuYi == true { + SendHUyi(telNum, code, templateId) + return code, nil + } + + fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code) + return code, mobileTemplate.Send(telNum, templateId, sigNo, code) //return code, mobileTemplate.SendAlSms(telNum, mobile.Sign, mobile.AlTMP1, code) } +// 是否使用互联的网络 +func codeIsUseHuLian(templateId uint) (bool, uint) { + if huYiTemplateResolver == nil { + return false, templateId + } + + huYiTemplateId, ok := huYiTemplateResolver(templateId) + if ok == false || huYiTemplateId == 0 { + return false, templateId + } + + return true, huYiTemplateId +} func SendCustomSignNoMsg(telNum string, url string, m uint, sigNo uint) error { mobileTemplate := config.GetMobile() @@ -141,3 +179,87 @@ func SendCustomSignNoMsg(telNum string, url string, m uint, sigNo uint) error { return mobileTemplate.Send(telNum, m, sigNo, url) //return mobileTemplate.SendAlSms(telNum, mobile.Sign, mobile.AlTMP1, url) } + +// SendHUyi是否使用互联的网络 +func SendHUyi(tel, code string, templateId uint) { + // 你原来的逻辑:执行新平台发送 + tourl := "http://106.ihuyi.com/webservice/sms.php?method=Submit" + + realTemplateId := "319637" + // 构造请求参数(和 Python 完全对应) + values := url.Values{ + "method": {"Submit"}, + "account": {"C40220224"}, + "password": {"428f1fc1d9daa5e713f373545cbfb13a"}, + "mobile": {tel}, // 这里替换成你的手机号变量 + "templateid": {realTemplateId}, + "content": {code}, // 这里替换成你的短信内容变量 + "sign": {"苏州翼迅通网络"}, + "format": {"json"}, + } + + fmt.Println("================") + fmt.Println(values) + + // 编码数据(对应 Python urllib.parse.urlencode) + data := []byte(values.Encode()) + + // 发起 POST 请求 + req, err := http.NewRequest("POST", tourl, bytes.NewBuffer(data)) + if err != nil { + fmt.Println("创建请求失败:", err) + return + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + + // 执行请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + fmt.Println("请求发送失败:", err) + return + } + defer resp.Body.Close() + + // 读取响应 + resBody, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Println("读取响应失败:", err) + return + } + + // 打印结果 + fmt.Println(string(resBody)) + + // JSON 解析(对应 Python json.loads) + var result map[string]interface{} + err = json.Unmarshal(resBody, &result) + if err != nil { + fmt.Println("JSON 解析失败:", err) + return + } + + // 获取返回字段 + respCode, _ := result["code"].(float64) + respMessage, _ := result["msg"].(string) + smsid, _ := result["smsid"].(string) + + fmt.Println("================") + fmt.Println(result, respMessage) + + // 判断是否发送成功(code !=2 表示失败) + if respCode != 2 { + fmt.Println("发送短信失败", result) + return + } + fmt.Println("最终 更新 成功,smsid:", smsid) + + res := msg.SendMsgResponse{ + MsgNo: smsid, // 这里使用返回的 smsid 作为 MsgNo + } + + msg.ReportMsgWithSendFrom(res, tel, templateId, SIG_NO, code, "账号") + + // 2. 执行插入(对应 Python create) + return +} diff --git a/pkg/model/message/message_template_entity.go b/pkg/model/message/message_template_entity.go new file mode 100644 index 0000000..ee10398 --- /dev/null +++ b/pkg/model/message/message_template_entity.go @@ -0,0 +1,26 @@ +package message + +import ( + "time" + + "gorm.io/plugin/soft_delete" +) + +var ( + PlatFeige = "feige" // 飞鸽 + PlatFeigeIntel = "feige-intel" // 飞鸽国际 +) + +// TemplateMessageEntity 模版实体列表 +type TemplateMessageEntity struct { + ID uint32 `gorm:"primarykey"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11)" json:"deletedAt"` + Title string `gorm:"column:title;type:varchar(50) not null;default:'';comment:标题"` + TemplateId uint `gorm:"column:template_id;type:varchar(20) not null;default: ;comment:模版id,可以重复"` + HuYiTemplateId uint `gorm:"column:huyi_template_id;type:varchar(20) not null;default: ;comment:模版id,可以重复"` + Remark string `gorm:"column:remark;type:varchar(50) not null;default:'';comment:备注id"` + Status uint32 `gorm:"column:status;type:tinyint(2) not null;default:1;comment:状态"` + Plat string `gorm:"column:plat;type:varchar(20) not null; default:'';comment:平台"` +}