feat: 格式化短信服务

This commit is contained in:
Argo-Tianyi 2021-12-23 12:36:11 +08:00
parent 4b6b1e2d6e
commit ae746cd352
1 changed files with 101 additions and 105 deletions

View File

@ -7,120 +7,116 @@ using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace BootstrapAdmin.Web.Services.SMS
namespace BootstrapAdmin.Web.Services.SMS;
/// <summary>
/// 手机号登陆帮助类
/// </summary>
public class DefaultSMSProvider : ISMSProvider
{
private static readonly ConcurrentDictionary<string, AutoExpireValidateCode> _pool = new ConcurrentDictionary<string, AutoExpireValidateCode>();
/// <summary>
/// 手机号登陆帮助类
/// 获得 短信配置信息
/// </summary>
public class DefaultSMSProvider : ISMSProvider
public SMSOptions Options { get { return _options; } }
private readonly DefaultSMSOptions _options;
private readonly HttpClient _client;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration"></param>
/// <param name="factory"></param>
public DefaultSMSProvider(IConfiguration configuration, IHttpClientFactory factory)
{
private static readonly ConcurrentDictionary<string, AutoExpireValidateCode> _pool = new ConcurrentDictionary<string, AutoExpireValidateCode>();
/// <summary>
/// 获得 短信配置信息
/// </summary>
public SMSOptions Options { get { return _options; } }
private readonly DefaultSMSOptions _options;
private readonly HttpClient _client;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration"></param>
/// <param name="factory"></param>
public DefaultSMSProvider(IConfiguration configuration, IHttpClientFactory factory)
{
_options = configuration.GetSection(nameof(SMSOptions)).Get<DefaultSMSOptions>();
_client = factory.CreateClient();
}
/// <summary>
/// 下发验证码方法
/// </summary>
/// <param name="phoneNumber"></param>
/// <returns></returns>
public async Task<SMSResult> SendCodeAsync(string phoneNumber)
{
Options.Timestamp = (DateTimeOffset.UtcNow.Ticks - 621355968000000000) / 10000000;
Options.Phone = phoneNumber;
var requestParameters = new Dictionary<string, string?>()
{
{ "CompanyCode", _options.CompanyCode },
{ "Phone", Options.Phone },
{ "TimeStamp", Options.Timestamp.ToString() },
{ "Sign", Sign() }
};
var url = QueryHelpers.AddQueryString(Options.RequestUrl, requestParameters);
var req = await _client.GetAsync(url);
var content = await req.Content.ReadAsStringAsync();
#if !NETSTANDARD2_0
var result = JsonSerializer.Deserialize<DefaultSMSResult>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
#else
var result = JsonConvert.DeserializeObject<DefaultSMSResult>(content);
#endif
var ret = new SMSResult() { Result = result!.Code == 1, Msg = result.Msg };
if (ret.Result)
{
_pool.AddOrUpdate(Options.Phone, key => new AutoExpireValidateCode(Options.Phone, result.Data, Options.Expires, phone => _pool.TryRemove(phone, out var _)), (key, v) => v.Reset(result.Data));
}
else
{
new Exception(result.Msg).Format(new NameValueCollection()
{
["UserId"] = Options.Phone,
["url"] = url,
["content"] = content
});
}
return ret;
}
/// <summary>
/// 验证验证码方法
/// </summary>
/// <param name="phone">手机号</param>
/// <param name="code">验证码</param>
/// <returns></returns>
public bool Validate(string phone, string code) => _pool.TryGetValue(phone, out var signKey) && Hash($"{code}{_options.MD5Key}") == signKey.Code;
private string Sign()
{
return Hash($"{_options.CompanyCode}{Options.Phone}{Options.Timestamp}{_options.MD5Key}");
}
private static string Hash(string data)
{
using var md5 = MD5.Create();
var sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(data)));
sign = sign.Replace("-", "").ToLowerInvariant();
return sign;
}
private class DefaultSMSResult
{
public int Code { get; set; }
public string Data { get; set; } = "";
public string Msg { get; set; } = "";
}
_options = configuration.GetSection(nameof(SMSOptions)).Get<DefaultSMSOptions>();
_client = factory.CreateClient();
}
/// <summary>
///
/// 下发验证码方法
/// </summary>
public class DefaultSMSOptions : SMSOptions
/// <param name="phoneNumber"></param>
/// <returns></returns>
public async Task<SMSResult> SendCodeAsync(string phoneNumber)
{
/// <summary>
/// 获得/设置 公司编码
/// </summary>
public string CompanyCode { get; set; } = "";
Options.Timestamp = (DateTimeOffset.UtcNow.Ticks - 621355968000000000) / 10000000;
Options.Phone = phoneNumber;
var requestParameters = new Dictionary<string, string?>()
{
{ "CompanyCode", _options.CompanyCode },
{ "Phone", Options.Phone },
{ "TimeStamp", Options.Timestamp.ToString() },
{ "Sign", Sign() }
};
/// <summary>
/// 获得/设置 签名密钥
/// </summary>
public string MD5Key { get; set; } = "";
var url = QueryHelpers.AddQueryString(Options.RequestUrl, requestParameters);
var req = await _client.GetAsync(url);
var content = await req.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<DefaultSMSResult>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
var ret = new SMSResult() { Result = result!.Code == 1, Msg = result.Msg };
if (ret.Result)
{
_pool.AddOrUpdate(Options.Phone, key => new AutoExpireValidateCode(Options.Phone, result.Data, Options.Expires, phone => _pool.TryRemove(phone, out var _)), (key, v) => v.Reset(result.Data));
}
else
{
new Exception(result.Msg).Format(new NameValueCollection()
{
["UserId"] = Options.Phone,
["url"] = url,
["content"] = content
});
}
return ret;
}
/// <summary>
/// 验证验证码方法
/// </summary>
/// <param name="phone">手机号</param>
/// <param name="code">验证码</param>
/// <returns></returns>
public bool Validate(string phone, string code) => _pool.TryGetValue(phone, out var signKey) && Hash($"{code}{_options.MD5Key}") == signKey.Code;
private string Sign()
{
return Hash($"{_options.CompanyCode}{Options.Phone}{Options.Timestamp}{_options.MD5Key}");
}
private static string Hash(string data)
{
using var md5 = MD5.Create();
var sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(data)));
sign = sign.Replace("-", "").ToLowerInvariant();
return sign;
}
private class DefaultSMSResult
{
public int Code { get; set; }
public string Data { get; set; } = "";
public string Msg { get; set; } = "";
}
}
/// <summary>
///
/// </summary>
public class DefaultSMSOptions : SMSOptions
{
/// <summary>
/// 获得/设置 公司编码
/// </summary>
public string CompanyCode { get; set; } = "";
/// <summary>
/// 获得/设置 签名密钥
/// </summary>
public string MD5Key { get; set; } = "";
}