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

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&param2=2&param3=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类库地址
文章代码地址

发表评论

相关文章