using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Globalization; using System.Net; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Web; namespace New_College.Common { public class AliyunSmsSender { private string RegionId = "cn-hangzhou"; private string Version = "2017-05-25"; private string Action = "SendSms"; private string Format = "JSON"; private string Domain = "dysmsapi.aliyuncs.com"; private int MaxRetryNumber = 3; private bool AutoRetry = true; private const string SEPARATOR = "&"; private int TimeoutInMilliSeconds = 100000; private string AccessKeyId; private string AccessKeySecret; public AliyunSmsSender(string accessKeyId, string accessKeySecret) { this.AccessKeyId = accessKeyId; this.AccessKeySecret = accessKeySecret; } /// /// 发送短信 /// public async Task<(bool success, string response)> Send(SmsObject sms) { var paramers = new Dictionary(); paramers.Add("PhoneNumbers", sms.Mobile); paramers.Add("SignName", sms.Signature); paramers.Add("TemplateCode", sms.TempletKey); paramers.Add("TemplateParam", JsonConvert.SerializeObject(sms.Data)); paramers.Add("OutId", sms.OutId); paramers.Add("AccessKeyId", AccessKeyId); try { string url = GetSignUrl(paramers, AccessKeySecret); int retryTimes = 1; var reply = await HttpGetAsync(url); while (500 <= reply.StatusCode && AutoRetry && retryTimes < MaxRetryNumber) { url = GetSignUrl(paramers, AccessKeySecret); reply = await HttpGetAsync(url); retryTimes++; } if (!string.IsNullOrEmpty(reply.response)) { var res = JsonConvert.DeserializeObject>(reply.response); if (res != null && res.ContainsKey("Code") && "OK".Equals(res["Code"])) { return (true, response: reply.response); } } return (false, response: reply.response); } catch (Exception ex) { return (false, response: ex.Message); } } private string GetSignUrl(Dictionary parameters, string accessSecret) { var imutableMap = new Dictionary(parameters); imutableMap.Add("Timestamp", FormatIso8601Date(DateTime.Now)); imutableMap.Add("SignatureMethod", "HMAC-SHA1"); imutableMap.Add("SignatureVersion", "1.0"); imutableMap.Add("SignatureNonce", Guid.NewGuid().ToString()); imutableMap.Add("Action", Action); imutableMap.Add("Version", Version); imutableMap.Add("Format", Format); imutableMap.Add("RegionId", RegionId); IDictionary sortedDictionary = new SortedDictionary(imutableMap, StringComparer.Ordinal); StringBuilder canonicalizedQueryString = new StringBuilder(); foreach (var p in sortedDictionary) { canonicalizedQueryString.Append("&").Append(PercentEncode(p.Key)).Append("=").Append(PercentEncode(p.Value)); } StringBuilder stringToSign = new StringBuilder(); stringToSign.Append("GET"); stringToSign.Append(SEPARATOR); stringToSign.Append(PercentEncode("/")); stringToSign.Append(SEPARATOR); stringToSign.Append(PercentEncode(canonicalizedQueryString.ToString().Substring(1))); string signature = SignString(stringToSign.ToString(), accessSecret + "&"); imutableMap.Add("Signature", signature); return ComposeUrl(Domain, imutableMap); } private static string FormatIso8601Date(DateTime date) { return date.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.CreateSpecificCulture("en-US")); } /// /// 签名 /// public static string SignString(string source, string accessSecret) { using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(accessSecret.ToCharArray()))) { return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(source.ToCharArray()))); } } private static string ComposeUrl(string endpoint, Dictionary parameters) { StringBuilder urlBuilder = new StringBuilder(""); urlBuilder.Append("http://").Append(endpoint); if (-1 == urlBuilder.ToString().IndexOf("?")) { urlBuilder.Append("/?"); } string query = ConcatQueryString(parameters); return urlBuilder.Append(query).ToString(); } private static string ConcatQueryString(Dictionary parameters) { if (null == parameters) { return null; } StringBuilder sb = new StringBuilder(); foreach (var entry in parameters) { String key = entry.Key; String val = entry.Value; sb.Append(HttpUtility.UrlEncode(key, Encoding.UTF8)); if (val != null) { sb.Append("=").Append(HttpUtility.UrlEncode(val, Encoding.UTF8)); } sb.Append("&"); } int strIndex = sb.Length; if (parameters.Count > 0) sb.Remove(strIndex - 1, 1); return sb.ToString(); } public static string PercentEncode(string value) { StringBuilder stringBuilder = new StringBuilder(); string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; byte[] bytes = Encoding.GetEncoding("UTF-8").GetBytes(value); foreach (char c in bytes) { if (text.IndexOf(c) >= 0) { stringBuilder.Append(c); } else { stringBuilder.Append("%").Append( string.Format(CultureInfo.InvariantCulture, "{0:X2}", (int)c)); } } return stringBuilder.ToString(); } private async Task<(int StatusCode, string response)> HttpGetAsync(string url) { HttpClientHandler handler = new HttpClientHandler(); handler.Proxy = null; handler.AutomaticDecompression = DecompressionMethods.GZip; using (var http = new HttpClient(handler)) { http.Timeout = new TimeSpan(TimeSpan.TicksPerMillisecond * TimeoutInMilliSeconds); HttpResponseMessage response = await http.GetAsync(url); return ((int)response.StatusCode, await response.Content.ReadAsStringAsync()); } } public class SmsObject { /// /// 手机号 /// public string Mobile { set; get; } /// /// 签名 /// public string Signature { get; set; } /// /// 模板Key /// public string TempletKey { set; get; } /// /// 短信数据 /// public IDictionary Data { set; get; } /// /// 业务ID /// public string OutId { set; get; } } } }