using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using UnityEngine; public static class SignUtil { public static string LastPlainText { get; private set; } = ""; public static string GetSign(Dictionary parameters, string secret) { // 排序并拼接 var sorted = new SortedDictionary(parameters, StringComparer.Ordinal); sorted.Remove("sign"); // sign 不参与 StringBuilder sb = new StringBuilder(); foreach (var kv in sorted) sb.Append(kv.Key).Append(kv.Value); sb.Append(secret); // MD5 小写 using var md5 = System.Security.Cryptography.MD5.Create(); byte[] input = Encoding.UTF8.GetBytes(sb.ToString()); byte[] hash = md5.ComputeHash(input); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } public static string GetSign(IDictionary parameters, string secret) { // 拷贝并排除 sign var dict = parameters .Where(kv => !string.Equals(kv.Key, "sign", StringComparison.Ordinal)) .ToDictionary(kv => kv.Key, kv => kv.Value); // 按 key ASCII 排序(等同 PHP 的 ksort) var ordered = dict.OrderBy(k => k.Key, StringComparer.Ordinal); // 拼接 key + value var sb = new StringBuilder(); foreach (var kv in ordered) { string v = ToFlatString(kv.Value); sb.Append(kv.Key).Append(v); } // // 追加 AppSecret sb.Append(secret); // 记录签名原文,便于排错 LastPlainText = sb.ToString(); Debug.Log(LastPlainText); // MD5 小写32位 using var md5 = MD5.Create(); var bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(LastPlainText)); return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); } // 将值转成“紧凑字符串”,数组按紧凑 JSON(无空格)序列化 private static string ToFlatString(object val) { if (val == null) return ""; switch (val) { case string s: return s; case bool b: return b ? "true" : "false"; case Array a: return JsonArrayCompact(a); case IList l: return JsonArrayCompact(l.ToArray()); default: if (val is IFormattable f) return f.ToString(null, System.Globalization.CultureInfo.InvariantCulture); return val.ToString(); } } private static string JsonArrayCompact(Array arr) { var parts = new List(arr.Length); foreach (var x in arr) { if (x == null) { parts.Add("null"); continue; } if (x is string s) parts.Add($"\"{Escape(s)}\""); else if (x is bool b) parts.Add(b ? "true" : "false"); else if (x is IFormattable f) parts.Add(f.ToString(null, System.Globalization.CultureInfo.InvariantCulture)); else parts.Add($"\"{Escape(x.ToString())}\""); } return "[" + string.Join(",", parts) + "]"; } private static string Escape(string s) => s.Replace("\\", "\\\\").Replace("\"", "\\\""); }