1、初衷
开发中经常需要做一些接口的签名生成和校验工作,最开始的时候都是每个接口去按照约定单独实现,久而久之就变的非常难维护,因此就琢磨怎么能够写了一个比较通用的签名生成工具。
2、思路
采用链式调用的方式,使得签名的步骤可以动态拼凑组合。
3、直接看效果
//设置数据源 var signSource = new Dictionary<string, string>() { { "param1", "1" }, { "param3", "3+" }, { "param2", "2" } }; var signer = new HttpSigner(); signer.SetSignData(signSource); //设置数据源并配置规则 signer.SetSignData(signSource, setting => { //按参数名排序 //result --> param1 param2 param3 setting.IsOrderByWithKey = false; //是否对签名数据的参数值进行UrlEncode setting.IsDoUrlEncodeForSourceValue = false; //签名主体是否包含参数名 setting.IsSignTextContainKey = true; //签名主体中参数和参数值的连接符(需要启用IsSignTextContainKey) setting.SignTextKeyValueSeparator = "="; //签名主体中不同参数项的连接符 setting.SignTextItemSeparator = "&"; //以上都开启后 --> param1=1¶m2=2¶m3=3 //编码 setting.DefaultEncoding = Encoding.UTF8; }); //签名主体设置前缀 signer.SetSignData(signSource).SetSignTextPrefix("TestPrefix"); //签名主体设置后缀 signer.SetSignData(signSource).SetSignTextSuffix("TestSuffix"); //签名主体进行Base64 signer.SetSignData(signSource).SetSignTextBase64(); //签名主体进行MD5,(方法参数为签名结果是否转小写) signer.SetSignData(signSource).SetSignTextMD5(bool isToLower = true); //签名主体进行SHA1,(方法参数为签名结果是否转小写) signer.SetSignData(signSource).SetSignTextSHA1(bool isToLower = true); //获取签名结果 string signString = signer.SetSignData(signSource).GetSignResult(); //组合调用 string signString = signer.SetSignData(signSource).SetSignTextBase64().SetSignTextMD5().SetSignTextSHA1();
4、代码实现
HttpSignItem类
用于保存签名的参数集合。
namespace JiuLing.CommonLibs.Security.HttpSign { internal class HttpSignItem { public string Key { get; set; } public string Value { get; set; } public HttpSignItem(string key, string value) { Key = key; Value = value; } } }
HttpSignSetting类
用于签名的基本配置。
using System.Text; namespace JiuLing.CommonLibs.Security.HttpSign { /// <summary> /// 签名配置 /// </summary> public class HttpSignSetting { /// <summary> /// 是否按参数名进行排序 /// </summary> public bool IsOrderByWithKey { get; set; } = false; /// <summary> /// 是否对签名数据的参数值进行UrlEncode /// </summary> public bool IsDoUrlEncodeForSourceValue { get; set; } = false; /// <summary> /// 签名主体是否包含参数名 /// </summary> public bool IsSignTextContainKey { get; set; } = true; /// <summary> /// 签名主体中参数和参数值的连接符(需要启用IsSignTextContainKey) /// </summary> public string SignTextKeyValueSeparator { get; set; } = "="; /// <summary> /// 签名主体中不同参数项的连接符 /// </summary> public string SignTextItemSeparator { get; set; } = "&"; /// <summary> /// 编码 /// </summary> public Encoding DefaultEncoding { get; set; } = Encoding.UTF8; } }
HttpSigner类
签名组件的具体实现。
using System; using System.Collections.Generic; using System.Linq; namespace JiuLing.CommonLibs.Security.HttpSign { /// <summary> /// 网络请求签名工具 /// </summary> public class HttpSigner { /// <summary> /// 签名配置 /// </summary> private readonly HttpSignSetting _setting = new HttpSignSetting(); /// <summary> /// 最终的签名串 /// </summary> private string _signString; /// <summary> /// 设置签名数据 /// </summary> /// <param name="signSource">待签名的键值对</param> /// <param name="setting">配置签名规则</param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> public HttpSigner SetSignData(Dictionary<string, string> signSource, Action<HttpSignSetting> setting = null) { setting?.Invoke(_setting); if (_setting == null) { throw new ArgumentNullException("无效的签名配置", "setting"); } if (signSource == null || signSource.Count == 0) { throw new ArgumentException("待签名数据异常", nameof(signSource)); } var signSourceList = new List<HttpSignItem>(signSource.Count); foreach (var item in signSource) { var itemValue = item.Value; if (_setting.IsDoUrlEncodeForSourceValue) { itemValue = System.Web.HttpUtility.UrlEncode(itemValue, _setting.DefaultEncoding); } signSourceList.Add(new HttpSignItem(item.Key, itemValue)); } if (_setting.IsOrderByWithKey) { signSourceList = signSourceList.OrderBy(x => x.Key).ToList(); } if (_setting.IsSignTextContainKey) { _signString = string.Join(_setting.SignTextItemSeparator, signSourceList.Select(x => $"{x.Key}{_setting.SignTextKeyValueSeparator}{x.Value}")); } else { _signString = string.Join(_setting.SignTextItemSeparator, signSourceList.Select(x => x.Value)); } return this; } /// <summary> /// 签名主体设置前缀 /// </summary> /// <param name="input">前缀值</param> /// <returns></returns> public HttpSigner SetSignTextPrefix(string input) { _signString = $"{input}{_signString}"; return this; } /// <summary> /// 签名主体设置后缀 /// </summary> /// <param name="input">后缀值</param> /// <returns></returns> public HttpSigner SetSignTextSuffix(string input) { _signString = $"{_signString}{input}"; return this; } /// <summary> /// 签名主体设置后缀 /// </summary> /// <returns></returns> public HttpSigner SetUrlEncode() { _signString = System.Web.HttpUtility.UrlEncode(_signString, _setting.DefaultEncoding); return this; } /// <summary> /// 签名主体进行Base64 /// </summary> /// <returns></returns> public HttpSigner SetSignTextBase64() { _signString = Base64Utils.GetStringValue(_signString); return this; } /// <summary> /// 签名主体进行MD5 /// </summary> /// <param name="isToLower">签名结果是否转小写</param> /// <returns></returns> public HttpSigner SetSignTextMD5(bool isToLower = true) { if (isToLower) { _signString = MD5Utils.GetStringValueToLower(_signString); } else { _signString = MD5Utils.GetStringValueToUpper(_signString); } return this; } /// <summary> /// 签名主体进行SHA1 /// </summary> /// <param name="isToLower">签名结果是否转小写</param> /// <returns></returns> public HttpSigner SetSignTextSHA1(bool isToLower = true) { if (isToLower) { _signString = SHA1Utils.GetStringValueToLower(_signString); } else { _signString = SHA1Utils.GetStringValueToUpper(_signString); } return this; } /// <summary> /// 获取签名结果 /// </summary> /// <returns></returns> public string GetSignResult() { return _signString; } } }
5、附上仓库地址
以上代码包含在我的通用类库中,可以直接Nuget搜索JiuLing.CommonLibs安装。
GitHub类库地址
文章代码地址