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 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 logger) { _httpClientFactory = httpClientFactory; _configuration = configuration; _accessKeyId = "LTAI5tAqyWKcBcSvzpc1ZM72"; _accessKeySecret = "YZMSqsmMGlGZuHw5WU2tqt0mmIBX6h"; } /// /// 使用 Base64 图片进行三要素核验 /// public async Task Id3MetaVerifyAsync( string identifyNum, string userName, string faceBase64, string crop = "F") { if (faceBase64.Contains(",")) { faceBase64 = faceBase64[(faceBase64.IndexOf(',') + 1)..]; } var parameters = new SortedDictionary { { "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(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(faceDetail); return detail?.VerifyScore; } private static string ComputeSignature(SortedDictionary 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 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; } } }