diff --git a/Src/Dlhis.Basic/HttpUtillib.cs b/Src/Dlhis.Basic/HttpUtillib.cs new file mode 100644 index 00000000..184dd9cf --- /dev/null +++ b/Src/Dlhis.Basic/HttpUtillib.cs @@ -0,0 +1,425 @@ +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace HttpUtil +{ + public class HikResponse + { + public T Data { get; set; } + public string Code { get; set; } + public string Msg { get; set; } + } + + public class HttpUtillib + { + /// + /// 设置信息参数 + /// + /// 合作方APPKey + /// 合作方APPSecret + /// 平台IP + /// 平台端口,默认HTTPS的443端口 + /// 是否启用HTTPS协议,默认HTTPS + /// + public static void SetPlatformInfo(string appkey, string secret, string ip, int port = 443, bool isHttps = true) + { + _appkey = appkey; + _secret = secret; + _ip = ip; + _port = port; + _isHttps = isHttps; + + // 设置并发数,如不设置默认为2 + ServicePointManager.DefaultConnectionLimit = 512; + } + + /// + /// HTTP GET请求 + /// + /// HTTP接口Url,不带协议和端口,如/artemis/api/resource/v1/cameras/indexCode?cameraIndexCode=a10cafaa777c49a5af92c165c95970e0 + /// 请求超时时间,单位:秒 + /// + public static byte[] HttpGet(string uri, int timeout) + { + Dictionary header = new Dictionary(); + + // 初始化请求:组装请求头,设置远程证书自动验证通过 + initRequest(header, uri, "", false); + + // build web request object + var sb = new StringBuilder(); + sb.Append(_isHttps ? "https://" : "http://").Append(_ip).Append(":").Append(_port.ToString()).Append(uri); + + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(sb.ToString()); + req.KeepAlive = false; + req.ProtocolVersion = HttpVersion.Version11; + req.AllowAutoRedirect = false; // 不允许自动重定向 + req.Method = "GET"; + req.Timeout = timeout * 1000; // 传入是秒,需要转换成毫秒 + req.Accept = header["Accept"]; + req.ContentType = header["Content-Type"]; + + foreach (string headerKey in header.Keys) + { + if (headerKey.Contains("x-ca-")) + { + req.Headers.Add(headerKey + ":" + header[headerKey]); + } + } + + HttpWebResponse rsp = null; + try + { + rsp = (HttpWebResponse)req.GetResponse(); + if (HttpStatusCode.OK == rsp.StatusCode) + { + Stream rspStream = rsp.GetResponseStream(); // 响应内容字节流 + StreamReader sr = new StreamReader(rspStream); + string strStream = sr.ReadToEnd(); + long streamLength = strStream.Length; + byte[] response = System.Text.Encoding.UTF8.GetBytes(strStream); + rsp.Close(); + return response; + } + else if (HttpStatusCode.Found == rsp.StatusCode || HttpStatusCode.Moved == rsp.StatusCode) // 302/301 redirect + { + string reqUrl = rsp.Headers["Location"].ToString(); // 获取重定向URL + WebRequest wreq = WebRequest.Create(reqUrl); // 重定向请求对象 + WebResponse wrsp = wreq.GetResponse(); // 重定向响应 + long streamLength = wrsp.ContentLength; // 重定向响应内容长度 + Stream rspStream = wrsp.GetResponseStream(); // 响应内容字节流 + byte[] response = new byte[streamLength]; + rspStream.Read(response, 0, (int)streamLength); // 读取响应内容至byte数组 + rspStream.Close(); + rsp.Close(); + return response; + } + + rsp.Close(); + } + catch (WebException e) + { + if (rsp != null) + { + rsp.Close(); + } + } + + return null; + } + + /// + /// HTTP Post请求 + /// + /// HTTP接口Url,不带协议和端口,如/artemis/api/resource/v1/org/advance/orgList + /// 请求参数 + /// 请求超时时间,单位:秒 + /// 请求结果 + public static byte[] HttpPost(string uri, string body, int timeout) + { + Dictionary header = new Dictionary(); + + // 初始化请求:组装请求头,设置远程证书自动验证通过 + initRequest(header, uri, body, true); + + // build web request object + StringBuilder sb = new StringBuilder(); + sb.Append(_isHttps ? "https://" : "http://").Append(_ip).Append(":").Append(_port.ToString()).Append(uri); + + // 创建POST请求 + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(sb.ToString()); + req.KeepAlive = false; + req.ProtocolVersion = HttpVersion.Version11; + req.AllowAutoRedirect = false; // 不允许自动重定向 + req.Method = "POST"; + req.Timeout = timeout * 1000; // 传入是秒,需要转换成毫秒 + req.Accept = header["Accept"]; + req.ContentType = header["Content-Type"]; + + foreach (string headerKey in header.Keys) + { + if (headerKey.Contains("x-ca-")) + { + req.Headers.Add(headerKey + ":" + header[headerKey]); + } + } + + if (!string.IsNullOrWhiteSpace(body)) + { + byte[] postBytes = Encoding.UTF8.GetBytes(body); + req.ContentLength = postBytes.Length; + Stream reqStream = null; + + try + { + reqStream = req.GetRequestStream(); + reqStream.Write(postBytes, 0, postBytes.Length); + reqStream.Close(); + } + catch (WebException e) + { + if (reqStream != null) + { + reqStream.Close(); + } + + return null; + } + } + + HttpWebResponse rsp = null; + try + { + rsp = (HttpWebResponse)req.GetResponse(); + if (HttpStatusCode.OK == rsp.StatusCode) + { + Stream rspStream = rsp.GetResponseStream(); + StreamReader sr = new StreamReader(rspStream); + string strStream = sr.ReadToEnd(); + long streamLength = strStream.Length; + byte[] response = System.Text.Encoding.UTF8.GetBytes(strStream); + rsp.Close(); + return response; + } + else if (HttpStatusCode.Found == rsp.StatusCode || HttpStatusCode.Moved == rsp.StatusCode) // 302/301 redirect + { + try + { + string reqUrl = rsp.Headers["Location"].ToString(); // 如需要重定向URL,请自行修改接口返回此参数 + rsp.Close(); + WebRequest wreq = WebRequest.Create(reqUrl); + rsp = (HttpWebResponse)wreq.GetResponse(); + Stream rspStream = rsp.GetResponseStream(); + long streamLength = rsp.ContentLength; + int offset = 0; + byte[] response = new byte[streamLength]; + while (streamLength > 0) + { + int n = rspStream.Read(response, offset, (int)streamLength); + if (0 == n) + { + break; + } + + offset += n; + streamLength -= n; + } + + return response; + } + catch(Exception e) + { + rsp.Close(); + return null; + } + } + + rsp.Close(); + } + catch (WebException e) + { + if (rsp != null) + { + rsp.Close(); + } + } + + return null; + } + + private static void initRequest(Dictionary header, string url, string body, bool isPost) + { + // Accept + string accept = "application/json";// "*/*"; + header.Add("Accept", accept); + + // ContentType + string contentType = "application/json"; + header.Add("Content-Type", contentType); + + if (isPost) + { + // content-md5,be careful it must be lower case. + string contentMd5 = computeContentMd5(body); + header.Add("content-md5", contentMd5); + } + + // x-ca-timestamp + string timestamp = ((DateTime.Now.Ticks - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0)).Ticks) / 1000).ToString(); + header.Add("x-ca-timestamp", timestamp); + + // x-ca-nonce + string nonce = System.Guid.NewGuid().ToString(); + header.Add("x-ca-nonce", nonce); + + // x-ca-key + header.Add("x-ca-key", _appkey); + + // build string to sign + string strToSign = buildSignString(isPost ? "POST" : "GET", url, header); + string signedStr = computeForHMACSHA256(strToSign, _secret); + + // x-ca-signature + header.Add("x-ca-signature", signedStr); + + if (_isHttps) + { + // set remote certificate Validation auto pass + ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(remoteCertificateValidate); + // FIX:修复不同.Net版对一些SecurityProtocolType枚举支持情况不一致导致编译失败等问题,这里统一使用数值 + ServicePointManager.SecurityProtocol = (SecurityProtocolType)48 | (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192; + //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; + } + } + + /// + /// 计算content-md5 + /// + /// + /// base64后的content-md5 + private static string computeContentMd5(string body) + { + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] result = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body)); + return Convert.ToBase64String(result); + } + + /// + /// 远程证书验证 + /// + /// + /// + /// + /// + /// 验证是否通过,始终通过 + private static bool remoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) + { + return true; + } + + /// + /// 计算HMACSHA265 + /// + /// 待计算字符串 + /// 平台APPSecet + /// HMAXH265计算结果字符串 + private static string computeForHMACSHA256(string str, string secret) + { + var encoder = new System.Text.UTF8Encoding(); + byte[] secretBytes = encoder.GetBytes(secret); + byte[] strBytes = encoder.GetBytes(str); + var opertor = new HMACSHA256(secretBytes); + byte[] hashbytes = opertor.ComputeHash(strBytes); + return Convert.ToBase64String(hashbytes); + } + + /// + /// 计算签名字符串 + /// + /// HTTP请求方法,如“POST” + /// 接口Url,如/artemis/api/resource/v1/org/advance/orgList + /// 请求头 + /// 签名字符串 + private static string buildSignString(string method, string url, Dictionary header) + { + StringBuilder sb = new StringBuilder(); + sb.Append(method.ToUpper()).Append("\n"); + if (null != header) + { + if (null != header["Accept"]) + { + sb.Append((string)header["Accept"]); + sb.Append("\n"); + } + + if (header.Keys.Contains("Content-MD5") && null != header["Content-MD5"]) + { + sb.Append((string)header["Content-MD5"]); + sb.Append("\n"); + } + + if (null != header["Content-Type"]) + { + sb.Append((string)header["Content-Type"]); + sb.Append("\n"); + } + + if (header.Keys.Contains("Date") && null != header["Date"]) + { + sb.Append((string)header["Date"]); + sb.Append("\n"); + } + } + + // build and add header to sign + string signHeader = buildSignHeader(header); + sb.Append(signHeader); + sb.Append(url); + return sb.ToString(); + } + + /// + /// 计算签名头 + /// + /// 请求头 + /// 签名头 + private static string buildSignHeader(Dictionary header) + { + Dictionary sortedDicHeader = new Dictionary(); + sortedDicHeader = header; + var dic = from objDic in sortedDicHeader orderby objDic.Key ascending select objDic; + + StringBuilder sbSignHeader = new StringBuilder(); + StringBuilder sb = new StringBuilder(); + foreach (KeyValuePair kvp in dic) + { + if (kvp.Key.Replace(" ", "").Contains("x-ca-")) + { + sb.Append(kvp.Key + ":"); + if (!string.IsNullOrWhiteSpace(kvp.Value)) + { + sb.Append(kvp.Value); + } + sb.Append("\n"); + if (sbSignHeader.Length > 0) + { + sbSignHeader.Append(","); + } + sbSignHeader.Append(kvp.Key); + } + } + + header.Add("x-ca-signature-headers", sbSignHeader.ToString()); + + return sb.ToString(); + } + + /// + /// 平台ip + /// + private static string _ip; + + /// + /// 平台端口 + /// + private static int _port = 443; + + /// + /// 平台APPKey + /// + private static string _appkey; + + /// + /// 平台APPSecret + /// + private static string _secret; + + /// + /// 是否使用HTTPS协议 + /// + private static bool _isHttps = true; + } +} diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs index fbff304d..52debc37 100644 --- a/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs +++ b/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs @@ -1,6 +1,9 @@ -using Dlhis.Basic.Organization.Request; +using System.Text; +using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; using Dlhis.Basic.Organization.Services; +using HttpUtil; +using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -31,4 +34,16 @@ public class GainfoFacesController : ControllerBase { return await _gainfoFaceService.GetPageAsync(request); } + + [AllowAnonymous] + [HttpPost("test")] + public string TestAsync(GainfoFaceValidateRequest request) + { + HttpUtillib.SetPlatformInfo("27390082", "MLl7Dv7p5Pgc9XYI3r4O", "10.32.0.10", 443, true); + + var r = HttpUtillib.HttpPost("/artemis/api/frs/v1/application/oneToOne", request.ToJson(), 15); + var rs = Encoding.UTF8.GetString(r); + + return rs; + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Request/GainfoFaceValidateRequest.cs b/Src/Dlhis.Basic/Organization/Request/GainfoFaceValidateRequest.cs new file mode 100644 index 00000000..b2c5f6f9 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Request/GainfoFaceValidateRequest.cs @@ -0,0 +1,7 @@ +namespace Dlhis.Basic.Organization.Request; + +public class GainfoFaceValidateRequest +{ + public string SrcFacePicBinaryData { get; set; } + public string DistFacePicBinaryData { get; set; } +} \ No newline at end of file