通用 HTTP 签名组件的另类实现

1、初衷开发中经常需要做一些接口的签名生成和校验工作 , 最开始的时候都是每个接口去按照约定单独实现 , 久而久之就变的非常难维护 , 因此就琢磨怎么能够写了一个比较通用的签名生成工具 。
2、思路【通用 HTTP 签名组件的另类实现】采用链式调用的方式 , 使得签名的步骤可以动态拼凑组合 。
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 param3setting.IsOrderByWithKey = false;//是否对签名数据的参数值进行UrlEncodesetting.IsDoUrlEncodeForSourceValue = https://www.huyubaike.com/biancheng/false;//签名主体是否包含参数名setting.IsSignTextContainKey = true;//签名主体中参数和参数值的连接符(需要启用IsSignTextContainKey)setting.SignTextKeyValueSeparator ="=";//签名主体中不同参数项的连接符setting.SignTextItemSeparator = "&";//以上都开启后--> param1=1&param2=2&param3=3//编码setting.DefaultEncoding = Encoding.UTF8;});//签名主体设置前缀signer.SetSignData(signSource).SetSignTextPrefix("TestPrefix");//签名主体设置后缀signer.SetSignData(signSource).SetSignTextSuffix("TestSuffix");//签名主体进行Base64signer.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 = https://www.huyubaike.com/biancheng/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 = https://www.huyubaike.com/biancheng/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;}}}

经验总结扩展阅读