Files
jinko.yikatong/Src/Dlhis.Basic/Organization/Services/IAliyunClient.cs
2026-06-23 17:33:33 +08:00

200 lines
6.2 KiB
C#

using System.Security.Cryptography;
using System.Text;
using Dlhis.Basic.Organization.Response;
using Kurisu.AspNetCore.CustomClass;
using Newtonsoft.Json;
namespace Dlhis.Basic.Organization.Services;
public interface IAliyunClient : ISingletonDependency
{
Task<AliyunId3MetaVerifyResponse> Id3MetaVerifyAsync(
string identifyNum,
string userName,
string faceBase64,
string crop = "F");
}
public class AliyunClient : IAliyunClient
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
private readonly string _accessKeyId;
private readonly string _accessKeySecret;
private const string Endpoint = "cloudauth.aliyuncs.com";
private const string ApiVersion = "2019-03-07";
public AliyunClient(IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger<AliyunClient> logger)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_accessKeyId = "LTAI5tAqyWKcBcSvzpc1ZM72";
_accessKeySecret = "YZMSqsmMGlGZuHw5WU2tqt0mmIBX6h";
}
/// <summary>
/// 使用 Base64 图片进行三要素核验
/// </summary>
public async Task<AliyunId3MetaVerifyResponse> Id3MetaVerifyAsync(
string identifyNum,
string userName,
string faceBase64,
string crop = "F")
{
if (faceBase64.Contains(","))
{
faceBase64 = faceBase64[(faceBase64.IndexOf(',') + 1)..];
}
var parameters = new SortedDictionary<string, string>
{
{ "Action", "Id3MetaVerify" },
{ "Format", "JSON" },
{ "Version", ApiVersion },
{ "AccessKeyId", _accessKeyId },
{ "SignatureMethod", "HMAC-SHA1" },
{ "SignatureVersion", "1.0" },
{ "SignatureNonce", Guid.NewGuid().ToString("N") },
{ "Timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ") },
{ "ParamType", "normal" },
{ "IdentifyNum", identifyNum },
{ "UserName", userName },
{ "FacePicture", faceBase64 },
{ "Crop", crop }
};
var signature = ComputeSignature(parameters, "POST", _accessKeySecret);
var url = $"https://{Endpoint}/?Signature={PercentEncode(signature)}";
var bodyString = BuildBodyString(parameters);
using var fallbackClient = _httpClientFactory == null ? new HttpClient() : null;
var client = _httpClientFactory?.CreateClient() ?? fallbackClient;
client.DefaultRequestHeaders.Add("Host", Endpoint);
var content = new StringContent(bodyString, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync(url, content);
var rawResponse = await response.Content.ReadAsStringAsync();
return ParseResponse(rawResponse);
}
private static AliyunId3MetaVerifyResponse ParseResponse(string rawResponse)
{
var result = new AliyunId3MetaVerifyResponse
{
RawResponse = rawResponse
};
if (string.IsNullOrWhiteSpace(rawResponse))
{
return result;
}
try
{
var response = JsonConvert.DeserializeObject<AliyunId3MetaVerifyApiResponse>(rawResponse);
result.RequestId = response?.RequestId;
result.Code = response?.Code;
result.Message = response?.Message;
result.BizCode = response?.ResultObject?.BizCode;
result.Similarity = ParseVerifyScore(response?.ResultObject?.FaceDetail);
result.Passed = response?.ResultObject?.BizCode switch
{
"1" => true,
"2" or "3" => false,
_ => null
};
}
catch
{
result.Message = "阿里云响应不是合法JSON";
}
return result;
}
private static double? ParseVerifyScore(string faceDetail)
{
if (string.IsNullOrWhiteSpace(faceDetail))
{
return null;
}
var detail = JsonConvert.DeserializeObject<AliyunId3MetaVerifyFaceDetail>(faceDetail);
return detail?.VerifyScore;
}
private static string ComputeSignature(SortedDictionary<string, string> parameters, string httpMethod, string accessKeySecret)
{
var canonicalized = new StringBuilder();
foreach (var kv in parameters)
{
if (kv.Key == "Signature")
{
continue;
}
if (canonicalized.Length > 0)
{
canonicalized.Append('&');
}
canonicalized.Append(PercentEncode(kv.Key))
.Append('=')
.Append(PercentEncode(kv.Value));
}
var stringToSign = httpMethod + "&" + PercentEncode("/") + "&" + PercentEncode(canonicalized.ToString());
var signKey = accessKeySecret + "&";
using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(signKey));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
return Convert.ToBase64String(hash);
}
private static string BuildBodyString(SortedDictionary<string, string> parameters)
{
return string.Join("&", parameters
.Where(x => x.Key != "Signature")
.Select(x => PercentEncode(x.Key) + "=" + PercentEncode(x.Value)));
}
private static string PercentEncode(string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
return Uri.EscapeDataString(value)
.Replace("+", "%20")
.Replace("*", "%2A")
.Replace("%7E", "~");
}
private class AliyunId3MetaVerifyApiResponse
{
public string RequestId { get; set; }
public string Message { get; set; }
public string Code { get; set; }
public AliyunId3MetaVerifyResultObject ResultObject { get; set; }
}
private class AliyunId3MetaVerifyResultObject
{
public string BizCode { get; set; }
public string FaceDetail { get; set; }
}
private class AliyunId3MetaVerifyFaceDetail
{
[JsonProperty("verifyScore")]
public double? VerifyScore { get; set; }
}
}