-
C# 通用 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¶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安装 https://www.nuget.org/packages/JiuLing.CommonLibs/。 GitHub类库地址 https://github.com/JiuLing-zhang/JiuLing.CommonLibs 文章代码地址 https://github.com/JiuLing-zhang/JiuLing.CommonLibs/tree/main/src/Security/HttpSign
出处:https://www.cnblogs.com/JiuLing-zhang/p/16732526.html
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数