Selaa lähdekoodia

更换东吴发送短信渠道

xyxie 2 viikkoa sitten
vanhempi
commit
7937740cc2
4 muutettua tiedostoa jossa 338 lisäystä ja 5 poistoa
  1. 23 1
      controllers/user.go
  2. 19 1
      models/business_conf.go
  3. 137 0
      services/dongwu_sms.go
  4. 159 3
      services/sms.go

+ 23 - 1
controllers/user.go

@@ -252,7 +252,29 @@ func (this *UserController) GetVerifyCode() {
 			return
 		}
 		if req.AreaCode == "86" {
-			ok = services.SendSmsCode(req.Phone, code)
+			smsClient, e := services.NewSmsClient()
+			if e != nil {
+				br.Msg = "短信发送失败"
+				br.ErrMsg = "短信发送失败,Err:" + e.Error()
+				return
+			}
+			//ok = services.SendSmsCode(req.Phone, code)
+			var smsReq services.UserLoginSmsCodeReq
+			smsReq.Mobile = req.Phone
+			smsReq.TelAreaCode = req.AreaCode
+			smsReq.VerifyCode = code
+			smsResult, e := smsClient.SendUserLoginCode(smsReq)
+			if e != nil {
+				br.Msg = "短信发送失败"
+				br.ErrMsg = "短信发送失败,Err:" + e.Error()
+				return
+			}
+			ok = smsResult.Success
+			if !ok {
+				br.Msg = "短信发送失败"
+				br.ErrMsg = "短信发送失败," + smsResult.Message
+				return
+			}
 		}
 		if !ok {
 			br.Msg = "请检查手机号和区号"

+ 19 - 1
models/business_conf.go

@@ -1,6 +1,8 @@
 package models
 
-import "time"
+import (
+	"time"
+)
 
 // BusinessConf 商户配置表
 type BusinessConf struct {
@@ -12,3 +14,19 @@ type BusinessConf struct {
 	Remark     string `description:"备注"`
 	CreateTime time.Time
 }
+
+const (
+	BusinessConfSmsJhgnAppKey             = "SmsJhgnAppKey"
+	BusinessConfSmsJhgjAppKey             = "SmsJhgjAppKey"
+	BusinessConfLoginSmsTplContent        = "LoginSmsTplContent"
+	BusinessConfSmsJhgjVariable           = "SmsJhgjVariable" // 聚合国际短信变量
+	BusinessConfSmsClient                 = "SmsClient"      // 短信客户端
+	BusinessConfLoginSmsTpId              = "LoginSmsTpId"
+	BusinessConfLoginSmsGjTpId            = "LoginSmsGjTpId" // 聚合国际短信模板ID
+	BusinessConfDongwuSmsAppKey          = "DongWuSmsAppKey"    // 东吴短信AppKey
+	BusinessConfDongwuSmsApiUrl          = "DongWuSmsApiUrl"    // 东吴短信API地址
+)
+
+const (
+	BusinessConfClientFlagDongwu       = "dwqh" // 东吴期货
+)

+ 137 - 0
services/dongwu_sms.go

@@ -0,0 +1,137 @@
+package services
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"eta/eta_mini_api/models"
+	"eta/eta_mini_api/utils"
+)
+
+type DongWuSms struct{}
+
+func (cli *DongWuSms) SendUserLoginCode(req UserLoginSmsCodeReq) (result UserLoginSmsCodeResult, err error) {
+	if req.Mobile == "" || req.VerifyCode == "" {
+		err = fmt.Errorf("参数有误, Mobile: %s, VerifyCode: %s", req.Mobile, req.VerifyCode)
+		return
+	}
+	// Get configuration
+	confMap, e := models.GetEtaConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+	tpl := confMap[models.BusinessConfLoginSmsTplContent]
+	if tpl == "" {
+		err = fmt.Errorf("请先配置短信模板")
+		return
+	}
+	
+	appKey := confMap[models.BusinessConfDongwuSmsAppKey]
+	if appKey == "" {
+		err = fmt.Errorf("请先配置东吴短信AppKey")
+		return
+	}
+	
+
+	// Call DongWu SMS API
+	apiURL := confMap[models.BusinessConfDongwuSmsApiUrl]
+	if apiURL == "" {
+		err = fmt.Errorf("请先配置东吴短信API地址")
+		return
+	}
+
+	// 短信内容
+	smsContent := strings.Replace(tpl, "{{VERIFY_CODE}}", req.VerifyCode, 1)
+	smsContent = strings.Replace(smsContent, "{{EXPIRED_MINUTE}}", strconv.Itoa(utils.VerifyCodeExpireMinute), 1)
+	apiResp, err := cli.sendUserLoginCode(req.Mobile, apiURL, appKey, smsContent)
+	if err != nil {
+		return
+	}
+	if apiResp.Status == "success" {
+		if apiResp.Result.Result == 0 {
+			result.Success = true
+			result.Message = apiResp.Result.Desc
+		}else{
+			result.Success = false
+			result.Message = fmt.Sprintf("发送失败, 错误码: %d, 错误信息: %s", apiResp.Result.Result, apiResp.Result.Desc)
+		}
+		return
+	}else{
+		result.Success = false
+		result.Message = apiResp.Message
+	}
+
+	return
+}
+
+type DongWuSmsApiParams struct {
+	GeneralAccount string `json:"generalAccount"`
+	Receivers string `json:"receivers"`
+	Text string `json:"text"`
+	
+	SubCode string `json:"subCode"`
+	SmsId string `json:"smsId"` //短信编号	(32 位 UUID),需保证唯一,选填
+	SendTime string `json:"sendTime"` // 选填,定时发送时间,格式 yyyyMMddHHmm,为空或早于当前时间则 立即发送;
+	Sign string `json:"sign"` // 选填,短信签名,为空时使用默认签名,默认为【东吴期货】
+}
+
+type DongWuSmsApiResult struct {
+	Status    string    `json:"status"`
+	Message string `json:"message"`
+	SmsType string `json:"smsType"` //短信平台类型,仅当status=”success”时不为空,“ssdj”代表三三得九平台,“dh3t”代表大汉三通平台
+	Result    struct {
+		Msgid string `json:"msgid"`
+		Result int `json:"result"`
+		Desc string `json:"desc"`
+		FailPhones string `json:"failPhones"`
+	} `json:"result"`
+}
+
+func (cli *DongWuSms) sendUserLoginCode(mobile, apiURL, appKey, content string) (apiResp *DongWuSmsApiResult, err error) {
+	// Prepare request parameters
+	params := DongWuSmsApiParams{
+		GeneralAccount:  appKey,
+		Receivers:     mobile,
+		Text:   content,
+	}
+
+	// Make HTTP request
+	jsonData, e := json.Marshal(params)
+	if e != nil {
+		err = fmt.Errorf("json marshal err: %s", e.Error())
+		return
+	}
+
+	httpReq, e := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
+	if e != nil {
+		err = fmt.Errorf("create request err: %s", e.Error())
+		return
+	}
+
+	httpReq.Header.Set("Content-Type", "application/json")
+	client := &http.Client{}
+	resp, e := client.Do(httpReq)
+	if e != nil {
+		err = fmt.Errorf("send request err: %s", e.Error())
+		return
+	}
+	defer resp.Body.Close()
+
+	body, e := ioutil.ReadAll(resp.Body)
+	if e != nil {
+		err = fmt.Errorf("read response err: %s", e.Error())
+		return
+	}
+	apiResp = &DongWuSmsApiResult{}
+	if e = json.Unmarshal(body, &apiResp); e != nil {
+		err = fmt.Errorf("parse response err: %s", e.Error())
+		return
+	}
+	return
+}

+ 159 - 3
services/sms.go

@@ -7,6 +7,9 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/url"
+	"strings"
+
+	"eta/eta_mini_api/models"
 )
 
 func SendSmsCode(mobile, vcode string) bool {
@@ -16,7 +19,7 @@ func SendSmsCode(mobile, vcode string) bool {
 		tplId = "262642"
 	}
 	expiresTime := "15"
-	result, err := sendSms(mobile, tplId, vcode, expiresTime)
+	result, err := sendSms(utils.JhGnAppKey, mobile, tplId, vcode, expiresTime)
 	if err != nil {
 		fmt.Println("发送短信失败")
 		return false
@@ -38,7 +41,7 @@ func SendSmsCode(mobile, vcode string) bool {
 	return flag
 }
 
-func sendSms(mobile, tplId, code, expirdTime string) (rs []byte, err error) {
+func sendSms(jhGnAppKey, mobile, tplId, code, expirdTime string) (rs []byte, err error) {
 	var Url *url.URL
 	apiURL := "http://v.juhe.cn/sms/send"
 	//初始化参数
@@ -47,7 +50,7 @@ func sendSms(mobile, tplId, code, expirdTime string) (rs []byte, err error) {
 	param.Set("mobile", mobile)                                  //接受短信的用户手机号码
 	param.Set("tpl_id", tplId)                                   //您申请的短信模板ID,根据实际情况修改
 	param.Set("tpl_value", "#code#="+code+"&"+"#m#="+expirdTime) //您设置的模板变量,根据实际情况
-	param.Set("key", utils.JhGnAppKey)                           //应用APPKEY(应用详细页查询)
+	param.Set("key", jhGnAppKey)                           //应用APPKEY(应用详细页查询)
 
 	Url, err = url.Parse(apiURL)
 	if err != nil {
@@ -64,3 +67,156 @@ func sendSms(mobile, tplId, code, expirdTime string) (rs []byte, err error) {
 	defer resp.Body.Close()
 	return ioutil.ReadAll(resp.Body)
 }
+
+// sendSmsGj 发送国际短信
+func sendSmsGj(jhGjAppKey, mobile, code, areaNum, tplId, tplValue string) (rs []byte, err error) {
+	var Url *url.URL
+	apiURL := "http://v.juhe.cn/smsInternational/send.php"
+	//初始化参数
+	param := url.Values{}
+	//配置请求参数,方法内部已处理urlencode问题,中文参数可以直接传参
+	param.Set("mobile", mobile) //接受短信的用户手机号码
+	//param.Set("tplId", "10054")           //您申请的短信模板ID,根据实际情况修改
+	param.Set("tplId", tplId) //您申请的短信模板ID,根据实际情况修改
+	if strings.Contains(tplValue, "#code#=%s") {
+		tplValue = strings.Replace(tplValue, "#code#=%s", "#code#="+code, 1)
+	}
+	if strings.Contains(tplValue, "#m#=%d") {
+		tplValue = strings.Replace(tplValue, "#m#=%d", fmt.Sprintf("#m#=%d", utils.VerifyCodeExpireMinute), 1)
+	}
+	//param.Set("tplValue", "#code#="+code) //您设置的模板变量,根据实际情况
+	param.Set("tplValue", tplValue) //您设置的模板变量,根据实际情况
+	param.Set("key", jhGjAppKey)    //应用APPKEY(应用详细页查询)
+	param.Set("areaNum", areaNum)   //应用APPKEY(应用详细页查询)
+
+	Url, err = url.Parse(apiURL)
+	if err != nil {
+		fmt.Printf("解析url错误:\r\n%v", err)
+		return nil, err
+	}
+	//如果参数中有中文参数,这个方法会进行URLEncode
+	Url.RawQuery = param.Encode()
+	resp, err := http.Get(Url.String())
+	if err != nil {
+		fmt.Println("err:", err)
+		return nil, err
+	}
+	utils.FileLog.Info("sendSmsGj:param:" + Url.String())
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	utils.FileLog.Info("sendSmsGj:result:" + string(body))
+	return body, err
+}
+
+type SmsClient interface {
+	SendUserLoginCode(UserLoginSmsCodeReq) (UserLoginSmsCodeResult, error)
+}
+
+func NewSmsClient() (cli SmsClient, err error) {
+	confMap, e := models.GetEtaConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+	if confMap[models.BusinessConfSmsClient] == models.BusinessConfClientFlagDongwu {
+		return new(DongWuSms), nil
+	}
+	return new(HzSms), nil
+}
+
+type HzSms struct{}
+
+type UserLoginSmsCodeReq struct {
+	TelAreaCode string `description:"区号"`
+	Mobile      string `description:"手机号"`
+	VerifyCode  string `description:"短信验证码"`
+}
+
+type UserLoginSmsCodeResult struct {
+	Success   bool   `description:"发送是否成功"`
+	Message   string `description:"提示信息"`
+	RequestId string `description:"发送ID,用于回查发送状态"`
+}
+
+// SendUserLoginCode 发送用户登录验证码
+func (cli *HzSms) SendUserLoginCode(req UserLoginSmsCodeReq) (result UserLoginSmsCodeResult, err error) {
+	if req.Mobile == "" || req.VerifyCode == "" {
+		err = fmt.Errorf("参数有误, Mobile: %s, VerifyCode: %s", req.Mobile, req.VerifyCode)
+		return
+	}
+	confMap, e := models.GetEtaConf()
+	if e != nil {
+		err = fmt.Errorf("GetBusinessConf err: %s", e.Error())
+		return
+	}
+
+	// 国内短信
+	var netReturn map[string]interface{}
+	if req.TelAreaCode == utils.TelAreaCodeHome {
+		tplId := confMap[models.BusinessConfLoginSmsTpId]
+		if tplId == "" {
+			err = fmt.Errorf("请先配置短信模板")
+			return
+		}
+		appKey := confMap[models.BusinessConfSmsJhgnAppKey]
+		if appKey == "" {
+			err = fmt.Errorf("请先配置聚合短信AppKey")
+			return
+		}
+
+		smsRes, e := sendSms(appKey, req.Mobile, tplId, req.VerifyCode, fmt.Sprintf("%d", utils.VerifyCodeExpireMinute))
+		if e != nil {
+			err = fmt.Errorf("send sms err: %s", e.Error())
+			return
+		}
+		if e = json.Unmarshal(smsRes, &netReturn); e != nil {
+			err = fmt.Errorf("json unmarshal err: %s", e.Error())
+			return
+		}
+	}
+
+	// 国际短信
+	if req.TelAreaCode != utils.TelAreaCodeHome {
+		tplId := confMap[models.BusinessConfLoginSmsGjTpId]
+		if tplId == "" {
+			err = fmt.Errorf("请先配置短信模板")
+			return
+		}
+		appKey := confMap[models.BusinessConfSmsJhgjAppKey]
+		if appKey == "" {
+			err = fmt.Errorf("请先配置聚合短信AppKey")
+			return
+		}
+		tplValue := confMap[models.BusinessConfSmsJhgjVariable]
+		if tplValue == "" {
+			// 默认初版变量
+			tplValue = "#code#=%s"
+		}
+
+		smsRes, e := sendSmsGj(appKey, req.Mobile, req.VerifyCode, req.TelAreaCode, tplId, tplValue)
+		if e != nil {
+			err = fmt.Errorf("send gj sms err: %s", e.Error())
+			return
+		}
+		if e = json.Unmarshal(smsRes, &netReturn); e != nil {
+			err = fmt.Errorf("json unmarshal err: %s", e.Error())
+			return
+		}
+	}
+
+	errCode, ok := netReturn["error_code"].(float64)
+	if !ok {
+		err = fmt.Errorf("result code err")
+		return
+	}
+	// 忽略错误的手机号码这种错误
+	if errCode != 0 && errCode != 205401 {
+		err = fmt.Errorf("err code %f", errCode)
+		return
+	}
+	// 发送成功
+	if errCode == 0 {
+		result.Success = true
+	}
+	return
+}