Files
AI-Health/backend/src/Health.Infrastructure/Services/bce_sms_client.cs
MingNian 32aae40b12 feat: 新增百度云 SMS v3 签名算法与 HttpClient 直连实现
- BceSigner: BCE v1 签名算法(HMAC-SHA256),与 baidubce-sdk 输出 byte-for-byte 一致
- BceSmsClient: HttpClient 直连百度云 SMS v3 API,自写签名,无第三方 SDK
- BceSignerTests: 7 个单测,包括真实 AK/SK 对比百度 SDK debug 输出

暂未启用:SmsService 仍为开发桩,等签名运营商实名报备后接入真实发送
2026-07-23 18:58:33 +08:00

65 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Globalization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Health.Infrastructure.Services;
/// <summary>
/// 百度云 SMS v3 短信发送客户端HttpClient 直连 + BCE v1 签名)
/// </summary>
public sealed class BceSmsClient(HttpClient http, IConfiguration cfg, ILogger<BceSmsClient> log)
{
private const string Path = "/api/v3/sendSms";
private const string ContentType = "application/json; charset=utf-8";
private readonly HttpClient _http = http;
private readonly ILogger<BceSmsClient> _log = log;
private readonly string _ak = cfg["BAIDU_SMS_AK"] ?? "";
private readonly string _sk = cfg["BAIDU_SMS_SK"] ?? "";
private readonly string _host = cfg["BAIDU_SMS_HOST"] ?? "smsv3.bj.baidubce.com";
private readonly string _signatureId = cfg["BAIDU_SMS_SIGNATURE_ID"] ?? "";
private readonly string _templateId = cfg["BAIDU_SMS_TEMPLATE_ID"] ?? "";
public async Task<bool> SendAsync(string phone, string code, CancellationToken ct)
{
var payload = new
{
mobile = $"+86{phone}",
template = _templateId,
signatureId = _signatureId,
contentVar = new { SMSvCode = code }
};
var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(payload));
using var req = new HttpRequestMessage(HttpMethod.Post, Path)
{
Content = new ByteArrayContent(body)
};
req.Content.Headers.TryAddWithoutValidation("Content-Type", ContentType);
req.Headers.Host = _host;
var now = DateTime.UtcNow;
var timestamp = now.ToString("yyyy-MM-ddTHH:mm:ss'Z'", CultureInfo.InvariantCulture);
req.Headers.Add("x-bce-date", timestamp);
var auth = BceSigner.BuildAuthorization(_ak, _sk, "POST", Path, _host, now, body.Length, ContentType);
req.Headers.TryAddWithoutValidation("Authorization", auth);
using var resp = await _http.SendAsync(req, ct);
var respBody = await resp.Content.ReadAsStringAsync(ct);
if (!resp.IsSuccessStatusCode)
{
_log.LogError("百度短信发送失败 HTTP {Status}: {Body}", resp.StatusCode, respBody);
return false;
}
using var doc = JsonDocument.Parse(respBody);
var respCode = doc.RootElement.GetProperty("code").GetString();
if (respCode != "1000")
{
_log.LogError("百度短信发送失败 code={Code}: {Body}", respCode, respBody);
return false;
}
return true;
}
}