SignUtils.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using Hotline.Share.Tools;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace TianQue.Sdk;
  9. public class SignUtils
  10. {
  11. private static readonly string SIGN_KEY = "_sign";
  12. private static readonly HashSet<string> SKIP_SIGN_PARAMS = new HashSet<string> { SIGN_KEY };
  13. public static string Sign(string appSecret, Dictionary<string, object> headers, string body)
  14. {
  15. var sorted = BuildSignSortedMap(headers, body);
  16. var stringBuilder = new StringBuilder();
  17. stringBuilder.Append(appSecret);
  18. string result = string.Join("",
  19. sorted.SelectMany(
  20. kvp => kvp.Value.Select(value => $"{kvp.Key}{value}")
  21. )
  22. );
  23. stringBuilder.Append(result);
  24. stringBuilder.Append(appSecret);
  25. var str = stringBuilder.ToString();
  26. return MD5Hex(str);
  27. }
  28. public static SortedDictionary<string, SortedSet<string>> BuildSignSortedMap(Dictionary<string, object> keyValueParams, string body)
  29. {
  30. var sortedMap = new SortedDictionary<string, SortedSet<string>>();
  31. if (keyValueParams != null && keyValueParams.Count > 0)
  32. {
  33. foreach (var entry in keyValueParams)
  34. {
  35. if (entry.Key != SIGN_KEY)
  36. {
  37. sortedMap[entry.Key] = new SortedSet<string>
  38. {
  39. entry.Value.ToString()
  40. };
  41. }
  42. }
  43. }
  44. if (!string.IsNullOrEmpty(body))
  45. {
  46. var a = new SortedSet<string>
  47. {
  48. body
  49. };
  50. sortedMap["_body"] = a;
  51. }
  52. return sortedMap;
  53. }
  54. private static string MD5Hex(string data)
  55. {
  56. using (var md5 = MD5.Create()) // 使用 MD5 哈希算法
  57. {
  58. byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(data)); // 将字符串转换为字节并计算哈希
  59. return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); // 转换为十六进制字符串(小写)
  60. }
  61. }
  62. public static string GenerateNonce()
  63. {
  64. // 生成随机 UUID 字符串
  65. string uuid = Guid.NewGuid().ToString();
  66. // 生成 10 个随机字符(包含字母和数字)
  67. string randomString = GenerateRandomString(10);
  68. // 使用 HMAC-SHA256 计算哈希值
  69. return ComputeHmacSha256(uuid, randomString);
  70. }
  71. private static string GenerateRandomString(int length)
  72. {
  73. const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  74. var random = new Random();
  75. var result = new StringBuilder(length);
  76. for (int i = 0;i < length;i++)
  77. {
  78. result.Append(chars[random.Next(chars.Length)]);
  79. }
  80. return result.ToString();
  81. }
  82. private static string ComputeHmacSha256(string key, string data)
  83. {
  84. // 将密钥和数据转换为字节数组
  85. byte[] keyBytes = Encoding.UTF8.GetBytes(key);
  86. byte[] dataBytes = Encoding.UTF8.GetBytes(data);
  87. // 使用 HMACSHA256 生成 HMAC 值
  88. using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
  89. {
  90. byte[] hashBytes = hmac.ComputeHash(dataBytes);
  91. // 将字节数组转换为十六进制字符串
  92. StringBuilder hex = new StringBuilder(hashBytes.Length * 2);
  93. foreach (byte b in hashBytes)
  94. {
  95. hex.AppendFormat("{0:x2}", b);
  96. }
  97. return hex.ToString();
  98. }
  99. }
  100. }