You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.3 KiB

package aliyun
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
const sortQueryStringFmt string = "AccessKeyId=%s" +
"&Action=SendSms" +
"&Format=JSON" +
"&OutId=123" +
"&PhoneNumbers=%s" +
"&RegionId=cn-hangzhou" +
"&SignName=%s" +
"&SignatureMethod=HMAC-SHA1" +
"&SignatureNonce=%s" +
"&SignatureVersion=1.0" +
"&TemplateCode=%s" +
"&TemplateParam=%s" +
"&Timestamp=%s" +
"&Version=2017-05-25"
func encodeLocal(encodeStr string) string {
urlEncode := url.QueryEscape(encodeStr)
urlEncode = strings.Replace(urlEncode, "+", "%%20", -1)
urlEncode = strings.Replace(urlEncode, "*", "%2A", -1)
urlEncode = strings.Replace(urlEncode, "%%7E", "~", -1)
urlEncode = strings.Replace(urlEncode, "/", "%%2F", -1)
return urlEncode
}
// SendSmsReply 发送短信返回
type SendSmsReply struct {
Code string `json:"Code,omitempty"`
Message string `json:"Message,omitempty"`
}
func SendSms(phone string, paramStr string, signName string, templateCode string, times int) error {
if times > 10 {
return errors.New("服务器繁忙")
}
const token string = "ZAnicsJ4biuCbgpNnqQbYU34FhTmn3&" // 阿里云 accessSecret 注意这个地方要添加一个 &
AccessKeyId := "LTAI5tLzNwMrdZUhdKpm9wor" // 自己的阿里云 accessKeyID
SignatureNonce := strconv.Itoa(GenerateRandNumByCount(9))
TemplateParam := url.QueryEscape(paramStr)
Timestamp := url.QueryEscape(time.Now().UTC().Format("2006-01-02T15:04:05Z"))
sortQueryString := fmt.Sprintf(sortQueryStringFmt,
AccessKeyId,
phone,
url.QueryEscape(signName),
SignatureNonce,
templateCode,
TemplateParam,
Timestamp,
)
urlencode := encodeLocal(sortQueryString)
sign_str := fmt.Sprintf("GET&%%2F&%s", urlencode)
key := []byte(token)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(sign_str))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
signature = encodeLocal(signature)
resp, err := http.Get("http://dysmsapi.aliyuncs.com/?Signature=" + signature + "&" + sortQueryString)
if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return err
}
ssr := &SendSmsReply{}
if err := json.Unmarshal(body, ssr); err != nil {
return err
}
if ssr.Code == "SignatureNonceUsed" {
return SendSms(phone, paramStr, signName, templateCode, times+1)
} else if ssr.Code != "OK" {
return errors.New(ssr.Code)
}
return nil
}
func GenerateRandNumByCount(count int) int {
rand.Seed(time.Now().Unix())
rnd := rand.Intn(9*int(exponent(10, uint64(count-1)))-1) + int(exponent(10, uint64(count-1)))
return rnd
}
func exponent(a, n uint64) uint64 {
result := uint64(1)
for i := n; i > 0; i >>= 1 {
if i&1 != 0 {
result *= a
}
a *= a
}
return result
}
func SendMessageNotice(phone string, content string, signName string, templateCode string) {
const token string = "IXvbHeyNLAWJHC08mg4quGYQtmf84h&" // 阿里云 accessSecret 注意这个地方要添加一个 &
AccessKeyId := "LTAIZSh7LB8zkmtO" // 自己的阿里云 accessKeyID
SignatureNonce := strconv.Itoa(GenerateRandNumByCount(9))
//TemplateCode := "SMS_140625198"
TemplateParam := url.QueryEscape("{\"content\":\"" + content + "\"}")
Timestamp := url.QueryEscape(time.Now().UTC().Format("2006-01-02T15:04:05Z"))
sortQueryString := fmt.Sprintf(sortQueryStringFmt,
AccessKeyId,
phone,
url.QueryEscape(signName),
SignatureNonce,
templateCode,
TemplateParam,
Timestamp,
)
urlEncode := encodeLocal(sortQueryString)
signStr := fmt.Sprintf("GET&%%2F&%s", urlEncode)
key := []byte(token)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(signStr))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
signature = encodeLocal(signature)
resp, err := http.Get("http://dysmsapi.aliyuncs.com/?Signature=" + signature + "&" + sortQueryString)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
ssr := &SendSmsReply{}
if err := json.Unmarshal(body, ssr); err != nil {
return
}
if ssr.Code == "SignatureNonceUsed" {
SendMessageNotice(phone, content, signName, templateCode)
return
} else if ssr.Code != "OK" {
return
}
return
}