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类库地址

文章代码地址

通用 HTTP 签名组件的另类实现的更多相关文章

  1. ASP.NET通用权限验证组件实现

    沙发(SF)通用权限验证组件 开篇 本篇介绍通用权限验证的实现代码思路,总共分为导入参数.解析XML.根据XML配置进行处理.返回结果. 代码架构图 1.   类介绍 1.SFWebPermissio ...

  2. SNFAutoupdater通用自动升级组件V2.0

    1.组件介绍 C/S构的特点是能充分发挥客户端的处理能力,很多工作可以由客户端处理后再提交给服务器,对应的优点就是客户端响应速度快模式客户端以其强大的功能,丰富的表现力受到相当大部分用户的青睐,但是客 ...

  3. 如何通过 Vue+Webpack 来做通用的前端组件化架构设计

    目录:   1. 架构选型     2. 架构目录介绍     3. 架构说明     4. 招聘消息 目前如果要说比较流行的前端架构哪家强,屈指可数:reactjs.angularjs.emberj ...

  4. 给 Web 开发人员推荐的通用独立 UI 组件(二)

    现代 Web 开发在将体验和功能做到极致的同时,对于美观的追求也越来越高.在推荐完图形库之后,再来推荐一些精品的独立 UI 组件.这些组件可组合在一起,形成美观而交互强大的 Web UI . 给 We ...

  5. Blazor组件自做二 : 使用JS隔离制作手写签名组件

    Blazor组件自做二 : 使用JS隔离制作手写签名组件 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazor组件自做一 : 使用JS隔离 ...

  6. Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件

    运行截图 演示地址 响应式演示 感谢szimek写的棒棒的signature_pad.js项目, 来源: https://github.com/szimek/signature_pad 正式开始 1. ...

  7. 《Nodejs开发加密货币》之二十七:开发通用的HTML组件

    人的懒惰常常是麻烦的开始.多数程序员都希望自己的工作一劳永逸,一次开发,到处使用,成了人人追逐的目标,我也不例外.最初写<Nodejs开发加密货币>系列文章,因为不喜欢设定好了去写,所以目 ...

  8. Tsx写一个通用的button组件

    一年又要到年底了,vue3.0都已经出来了,我们也不能一直还停留在过去的js中,是时候学习并且在项目中使用一下Ts了. 如果说jsx是基于js的话,那么tsx就是基于typescript的 废话也不多 ...

  9. 容器扩展属性 IExtenderProvider 实现WinForm通用数据验证组件

    大家对如下的Tip组件使用应该不陌生,要想让窗体上的控件使用ToolTip功能,只需要拖动一个ToolTip组件到窗口,所有的控件就可以使用该功能,做信息提示. 本博文要记录的,就是通过容器扩展属性 ...

随机推荐

  1. LCA——树上倍增

    首先,什么是LCA? LCA:最近公共祖先 祖先:从当前点到根节点所经过的点,包括他自己,都是这个点的祖先 A和B的公共祖先:同时是A,B两点的祖先的点 A和B的最近公共祖先:深度最大的A和B的公共祖 ...

  2. Cow Picnic S

    题目描述: K(1≤K≤100)只奶牛分散在N(1≤N≤1000)个牧场.现在她们要集中起来进餐.牧场之间有M(1≤M≤10000)条有向路连接,而且不存在起点和终点相同的有向路.她们进餐的地点必须是 ...

  3. CF242E XOR on Segment

    CF242E XOR on Segment codeforces 洛谷 关于异或,无法运用懒标记实现区间异或: 可以像trie树一样拆位,将每个值拆成二进制数,对此建相应个数的线段树. 0 1与 0异 ...

  4. React报错之react component changing uncontrolled input

    正文从这开始~ 总览 当input的值被初始化为undefined,但后来又变更为一个不同的值时,会产生"A component is changing an uncontrolled in ...

  5. 【面试题】纯css实现三角形,你知道如何实现吗?

    纯css实现三角形 点击打开视频教程 <template> <div id="app"> <!-- 纯css实现三角形书写 --> <di ...

  6. JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析

    JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...

  7. C# 使用SIMD向量类型加速浮点数组求和运算(1):使用Vector4、Vector<T>

    作者: 目录 一.缘由 二.使用向量类型 2.1 基本算法 2.2 使用大小固定的向量(如 Vector4) 2.2.1 介绍 2.2.2 用Vector4编写浮点数组求和函数 2.3 使用大小与硬件 ...

  8. 入门 Socket.io

    概念 Socket.io 是一个支持客户端和服务器之间的低延迟.双向和基于事件的通信的库,除了支持 JavaScript 以外,还支持 Java.Python.Golang. Socket.io 构建 ...

  9. Canvas 非常重要的三个函数

    beginPath 绘制路径必须添加 beginPath().它标志着一个画笔在画布中哪个地方开始画起.没有它,新起的画笔位置必定与上一次画笔结束的位置相连. // 第一个半圆 ctx.arc(60, ...

  10. ansible 的安装及常见模块使用

    ansible 基础keys的ssh协议配置的 特性:幂等性:一个任务执行1遍和执行n遍效果一样. ansible是个管理软件不是服务,不需要长期运行  一.通过epel源安装ansible, 1.下 ...