134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
type SmsService struct{}
|
|
|
|
func NewSmsService() *SmsService {
|
|
return &SmsService{}
|
|
}
|
|
|
|
type SmsConfig struct {
|
|
Provider string
|
|
AccessKey string
|
|
SecretKey string
|
|
SignName string
|
|
TemplateCode string
|
|
}
|
|
|
|
func (s *SmsService) SendSms(config SmsConfig, phone, code string) error {
|
|
switch config.Provider {
|
|
case "aliyun":
|
|
return s.sendAliyunSms(config, phone, code)
|
|
case "tencent":
|
|
return s.sendTencentSms(config, phone, code)
|
|
case "huawei":
|
|
return s.sendHuaweiSms(config, phone, code)
|
|
default:
|
|
return fmt.Errorf("不支持的短信服务商: %s", config.Provider)
|
|
}
|
|
}
|
|
|
|
func (s *SmsService) sendAliyunSms(config SmsConfig, phone, code string) error {
|
|
params := url.Values{}
|
|
params.Set("AccessKeyId", config.AccessKey)
|
|
params.Set("Action", "SendSms")
|
|
params.Set("Format", "JSON")
|
|
params.Set("PhoneNumbers", phone)
|
|
params.Set("RegionId", "cn-hangzhou")
|
|
params.Set("SignName", config.SignName)
|
|
params.Set("SignatureMethod", "HMAC-SHA1")
|
|
params.Set("SignatureNonce", fmt.Sprintf("%d", getTimeStamp()))
|
|
params.Set("SignatureVersion", "1.0")
|
|
params.Set("TemplateCode", config.TemplateCode)
|
|
params.Set("TemplateParam", fmt.Sprintf(`{"code":"%s"}`, code))
|
|
params.Set("Timestamp", getTimeStampStr())
|
|
params.Set("Version", "2017-05-25")
|
|
|
|
signature := s.generateAliyunSignature(params, config.SecretKey)
|
|
params.Set("Signature", signature)
|
|
|
|
resp, err := http.Get(fmt.Sprintf("https://dysmsapi.aliyuncs.com/?%s", params.Encode()))
|
|
if err != nil {
|
|
return fmt.Errorf("请求阿里云短信API失败: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("读取响应失败: %v", err)
|
|
}
|
|
|
|
var result struct {
|
|
Code string `json:"Code"`
|
|
Message string `json:"Message"`
|
|
}
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
return fmt.Errorf("解析响应失败: %v", err)
|
|
}
|
|
|
|
if result.Code != "OK" {
|
|
return fmt.Errorf("发送失败: %s", result.Message)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *SmsService) generateAliyunSignature(params url.Values, secretKey string) string {
|
|
keys := make([]string, 0, len(params))
|
|
for k := range params {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
encodedParams := make([]string, 0, len(params))
|
|
for _, k := range keys {
|
|
encodedParams = append(encodedParams, fmt.Sprintf("%s=%s", specialUrlEncode(k), specialUrlEncode(params.Get(k))))
|
|
}
|
|
sortParams := strings.Join(encodedParams, "&")
|
|
|
|
stringToSign := fmt.Sprintf("GET&%s&%s", specialUrlEncode("/"), specialUrlEncode(sortParams))
|
|
|
|
signature := hmacSHA1(secretKey+"&", stringToSign)
|
|
return signature
|
|
}
|
|
|
|
func (s *SmsService) sendTencentSms(config SmsConfig, phone, code string) error {
|
|
return fmt.Errorf("腾讯云短信服务暂未实现")
|
|
}
|
|
|
|
func (s *SmsService) sendHuaweiSms(config SmsConfig, phone, code string) error {
|
|
return fmt.Errorf("华为云短信服务暂未实现")
|
|
}
|
|
|
|
func (s *SmsService) SendTestSms(config SmsConfig, phone string) error {
|
|
code := "123456"
|
|
return s.SendSms(config, phone, code)
|
|
}
|
|
|
|
func specialUrlEncode(s string) string {
|
|
encoded := url.QueryEscape(s)
|
|
encoded = strings.ReplaceAll(encoded, "+", "%20")
|
|
encoded = strings.ReplaceAll(encoded, "*", "%2A")
|
|
encoded = strings.ReplaceAll(encoded, "%7E", "~")
|
|
return encoded
|
|
}
|
|
|
|
func hmacSHA1(key, data string) string {
|
|
return data
|
|
}
|
|
|
|
func getTimeStamp() int64 {
|
|
return 0
|
|
}
|
|
|
|
func getTimeStampStr() string {
|
|
return ""
|
|
}
|