Unity3D MD5 签名算法

news/2025/1/15 21:00:15/

Unity3D MD5 签名算法实现流程。

MD5 签名算法

之前在和运营对接支付订单模块时,需要向他们的服务器发送查单请求,其中有个参数是 sign,要求把订单的相关信息,转换成 MD5 的形式。

简要流程:

  1. 先对参数列表按照 ASCII 码排序
  2. 参数列表拼接成字符串,末尾拼接密钥
  3. 拼接后的字符串做 MD5 计算

参数列表排序

首先,假设有如下参数:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestMD5 : MonoBehaviour
{void Start(){Dictionary<string, object> args = new Dictionary<string, object>{["product_id"] = 100001,         // 产品 id["product_name"] = "金币礼包",    // 产品名称["amount"] = 1,                  // 数量["price"] = 600                  // 价格};}
}

现在需要先对字典中的参数按照 ASCII 码进行排序。

这里创建一个静态类 MD5Sign.cs 作为工具类使用。

添加方法 AsciiDicToStr,接收字典类型的参数,返回字符串。

引用 System.Linq 命名空间,可以扩展字典的方法,例如 ToArray,把字典的 key 值取出,变成数组。

利用 Array.Sort 进行排序(需要命名空间 System),传入参数 string.CompareOrdinal 就可以按照 ASCII 码从小到大进行排序了。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;public static class MD5Sign
{/// <summary>/// 以参数名的 ASCII 码从小到大排序并拼接/// </summary>/// <param name="args">参数列表</param>static string AsciiDicToStr(Dictionary<string, object> args){// 取出 key 集合并转换成数组string[] keysArray = args.Keys.ToArray();// 对 key 数组进行排序(ASCII 码从小到大)Array.Sort(keysArray, string.CompareOrdinal);return "";}
}

参数拼接字符串

继续扩展 AsciiDicToStr 方法。

引用命名空间 System.Text,就可以使用 StringBuilder 来拼接字符串了。

遍历 key 数组,按照 key=value& 的形式拼接,参数值为 null 或者 “” 不参与签名。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;public static class MD5Sign
{/// <summary>/// 以参数名的 ASCII 码从小到大排序并拼接/// </summary>/// <param name="args">参数列表</param>static string AsciiDicToStr(Dictionary<string, object> args){// 取出 key 集合并转换成数组string[] keysArray = args.Keys.ToArray();// 对 key 数组进行排序(ASCII 码从小到大)Array.Sort(keysArray, string.CompareOrdinal);// 按照排序后的 key 数组依次从字典中取出值进行拼接StringBuilder sb = new StringBuilder();foreach (var key in keysArray){string value = args[key]?.ToString();// 参数值为 null 或者 "" 不参与签名if (value != null && !string.Empty.Equals(value)){sb.Append(key);sb.Append("=");sb.Append(value);sb.Append("&");}}return sb.ToString();}
}

现在可以再添加一个方法 ComputeSign 提供给外部调用。

这里定义了一个密钥,内容是随便输入的,用于演示,通常情况下密钥不会放在客户端,防止被破解获取,应该放到服务端。

调用上面写的 AsciiDicToStr 方法,传入字典,得到 result,在末尾继续拼接 key=signKey

public static class MD5Sign
{// 密钥,通常应该放到服务端,此处为了演示先放客户端static string signKey = "abcdefg";/// <summary>/// 计算参数签名/// </summary>/// <param name="args">参数列表</param>public static string ComputeSign(Dictionary<string, object> args){// 按照 ASCII 码从小到大排序并拼接string result = AsciiDicToStr(args);// 拼接密钥result += $"key={signKey}";return result;}// ...
}

现在可以先调用这个方法,查看拼接后的结果。

public class TestMD5 : MonoBehaviour
{void Start(){Dictionary<string, object> args = new Dictionary<string, object>{["product_id"] = 100001,         // 产品 id["product_name"] = "金币礼包",    // 产品名称["amount"] = 1,                  // 数量["price"] = 600                  // 价格};string result = MD5Sign.ComputeSign(args);Debug.Log($"result = {result}");// result = amount=1&price=600&product_id=100001&product_name=金币礼包&key=abcdefg}
}

计算 MD5

在静态类 MD5Sign.cs 中继续添加方法 ComputeStringMD5,接收字符串,返回字符串。

在 C# 中,有提供用于加密算法的类,需要引用命名空间 System.Security.Cryptography

创建一个 MD5 对象,先通过 Encoding.UTF8.GetBytes 方法,把字符串转成 byte 数组,传给 MD5 对象的 ComputeHash 方法,同样得到 byte 数组,遍历这个 byte 数组,使用 ToString("X2") 的格式进行拼接(X2 表示使用大写十六进制,不足两位时前面补 0)。

因为 byte 数组的长度是 16,每个值都转成两位字符串,最终得到的就是 32 位字符串。

// ...
using System.Security.Cryptography;public static class MD5Sign
{// .../// <summary>/// 计算字符串的 MD5 值/// </summary>/// <param name="str">字符串</param>static string ComputeStringMD5(string str){StringBuilder sb = new StringBuilder();// 创建 MD5 对象using (MD5 md5 = MD5.Create()){// 字符串转 byte 数组byte[] buffer = Encoding.UTF8.GetBytes(str);// 计算 MD5 值byte[] mdBytes = md5.ComputeHash(buffer);md5.Clear();// 将 byte 数组中的每个元素以大写十六进制字符串的方式拼接for (int i = 0; i < mdBytes.Length; i++){sb.Append(mdBytes[i].ToString("X2"));}return sb.ToString();}}
}

最后把这个方法接入 ComputeSign 方法中。

public static class MD5Sign
{/// <summary>/// 计算参数签名/// </summary>/// <param name="args">参数列表</param>public static string ComputeSign(Dictionary<string, object> args){// 按照 ASCII 码从小到大排序并拼接string result = AsciiDicToStr(args);// 拼接密钥result += $"key={signKey}";// 计算拼接后的字符串的 MD5 值string md5 = ComputeStringMD5(result);return md5;}
}

现在调用这个方法就可以得到计算 MD5 之后的结果了。

public class TestMD5 : MonoBehaviour
{void Start(){Dictionary<string, object> args = new Dictionary<string, object>{["product_id"] = 100001,         // 产品 id["product_name"] = "金币礼包",    // 产品名称["amount"] = 1,                  // 数量["price"] = 600                  // 价格};string result = MD5Sign.ComputeSign(args);Debug.Log($"result = {result}");// result = EF4834EF466F73319545057E703E73E2}
}

完整代码

MD5Sign.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;public static class MD5Sign
{// 密钥,通常应该放到服务端,此处为了演示先放客户端static string signKey = "abcdefg";/// <summary>/// 计算参数签名/// </summary>/// <param name="args">参数列表</param>public static string ComputeSign(Dictionary<string, object> args){// 按照 ASCII 码从小到大排序并拼接string result = AsciiDicToStr(args);// 拼接密钥result += $"key={signKey}";// 计算拼接后的字符串的 MD5 值string md5 = ComputeStringMD5(result);return md5;}/// <summary>/// 以参数名的 ASCII 码从小到大排序并拼接/// </summary>/// <param name="args">参数列表</param>static string AsciiDicToStr(Dictionary<string, object> args){// 取出 key 集合并转换成数组string[] keysArray = args.Keys.ToArray();// 对 key 数组进行排序(ASCII 码从小到大)Array.Sort(keysArray, string.CompareOrdinal);// 按照排序后的 key 数组依次从字典中取出值进行拼接StringBuilder sb = new StringBuilder();foreach (var key in keysArray){string value = args[key]?.ToString();// 参数值为 null 或者 "" 不参与签名if (value != null && !string.Empty.Equals(value)){sb.Append(key);sb.Append("=");sb.Append(value);sb.Append("&");}}return sb.ToString();}/// <summary>/// 计算字符串的 MD5 值/// </summary>/// <param name="str">字符串</param>static string ComputeStringMD5(string str){StringBuilder sb = new StringBuilder();// 创建 MD5 对象using (MD5 md5 = MD5.Create()){// 字符串转 byte 数组byte[] buffer = Encoding.UTF8.GetBytes(str);// 计算 MD5 值byte[] mdBytes = md5.ComputeHash(buffer);md5.Clear();// 将 byte 数组中的每个元素以大写十六进制字符串的方式拼接for (int i = 0; i < mdBytes.Length; i++){sb.Append(mdBytes[i].ToString("X2"));}return sb.ToString();}}
}

http://www.ppmy.cn/news/1507460.html

相关文章

19-ESP32-C3加大固件储存区

1默认编译情况。 2、改flash4M。ESP-IDF Partition Table Editor修改。 3、设置输入Partition Table 改自定义.CSV。保存。 4、查看命令输入Partition Table Editor打开-分区表编辑器UI。按图片增加。 nvs,data,nvs,0x9000,0x6000,, phy_init,data,phy,0xF000,0x1000,, factory…

并发编程:使用Scala Future和Akka实现并发处理

并发编程&#xff1a;使用Scala Future和Akka实现并发处理 引言 并发编程是现代软件开发中的一个重要领域&#xff0c;尤其在处理大量数据和高性能计算时尤为关键。Scala语言以其强大的并发编程支持&#xff0c;成为解决此类问题的理想选择。本文将详细介绍如何使用Scala中的…

大厂面试题分享第二期

大厂面试题分享第二期 如果执行了一条命令&#xff0c;"select count(*)from…"&#xff0c;使用哪个引擎更快&#xff0c;为什么&#xff1f;垃圾回收器 CMS 和 G1的区别介绍一下CMS和G1CMS&#xff08;并发&#xff09;垃圾收集器G1垃圾回收器 HTTPS和HTTP的区别主…

leetcode169. 多数元素,摩尔投票法附证明

leetcode169. 多数元素 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,3] 输…

【前端学习笔记】CSS基础三

一、CSS变量 CSS变量&#xff0c;也称为CSS自定义属性&#xff0c;是CSS3的一部分&#xff0c;允许开发者在CSS中定义和使用变量。这些变量可以存储值&#xff0c;然后在整个文档中重复使用这些值。使用CSS变量可以提高样式表的可维护性&#xff0c;并且使得主题和设计变量的更…

七、OpenCVSharp 中的图像边缘检测

文章目录 简介一、Sobel 算子1. 水平和垂直方向的 Sobel 算子2. 梯度幅值和方向的计算3. Sobel 算子的参数调整和效果优化二、Canny 边缘检测1. Canny 算法的步骤详解(高斯平滑、梯度计算、非极大值抑制、双阈值检测)2. 高低阈值的选择对边缘检测结果的影响3. Canny 边缘检测…

Vue 3+Vite+Eectron从入门到实战系列之(三)一Electron热身运动(一)

前面我们已经把基础环境配置好了,在开始我们编写第一个页面之前,先尝试几个小的实验,体验下 electron 的乐趣。 更改我们应用的名称 系统默认的名字是从 package.json 中读取的,我们可以在这里更改。 {"name": "electron-vue3" }更改后,我们重新启动…

kubernets学习笔记——Kubernets 命令行工具 kubectl

目录 kubectl 的使用方法1、语法2、操作3、资源类型4、输出格式5、示例&#xff1a;常用操作6、示例&#xff1a;创建和使用插件 kubectl 的使用方法 Kubernetes 提供 kubectl 是使用 Kubernetes API 与 Kubernetes 集群的控制面进行通信的命令行工具。这个工具叫做 kubectl。通…