前言:

晚上打算睡觉的时候,群里反馈订单接收失败,开工排查问题,日志显示验签失败,发现一个蛮有意思的BUG,总算有了一个写作的素材

场景描述

本次的场景属于比较常见的收单API,对第三方的订单进行签名验证,然后持久化到数据库,签名规则大致是将参数key按照升序排序,然后根据key=value&进行字符串拼接,最后加上秘钥,按照指定的加密方式生成签名

前戏一

设计之初,肯定是怎么简单怎么来,粗略代码如下

[HttpPost]
public async Task<IActionResult> TestSendOrder([FromBody] ReceiveOrderRequest request)
{
var secret_key = _options.Value.SecretKey;
var url = _options.Value.Host;
//1.将模型转成json格式字符串
var param = JsonConvert.SerializeObject(request);
//2.将json格式字符串,序列化成有序字典
SortedDictionary<string, string> dict = JsonConvert.DeserializeObject<SortedDictionary<string, string>>(param);
//3.循环字典,按规则拼接成待加密的明文字符串
var data = "";
foreach (var item in dict)
{
if (item.Key == "sign") continue;
data += $"{item.Key}={item.Value}&";
}
data += $"secret_key={secret_key}";
//4.生成签名
var sign = EncryptHelper.SHA1Encryption(data);
request.sign = sign;
//5.模拟订单推送
var res = await _httpClientHelper.PostData(url, JsonConvert.SerializeObject(request));
return Ok(res);
}

不出意外,肯定是要出意外的,联调的时候,发现与第三方待加密的明文字符串不一致,问题出在JsonConvert序列化上,这里有两个问题

    1. DateTime格式不一致
如: DateTime dt = "2022-07-30 12:26:56"
序列化后 dt=2022-07-30T12:26:56
2. decimal小数点后自动补0
如: decimal price = 10
序列化后 price=10.0

针对第一个问题,很好解决,我们在序列化的时候,指定DateTime的格式即可

var iso = new IsoDateTimeConverter();
iso.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
var param = JsonConvert.SerializeObject(request, iso);

针对第二个问题,处理起来就比较麻烦了,要重写底层的一些东西(主要是我不会),这不符合"简单"的定义,得换个方案

前戏二

通过反射遍历对象,然后将属性名称与值,丢到有序字典里面,这里我写了个方法来判断值是否为时间,如果是时间类型,则格式化,代码如下

public string GetFmortDateTime(string strDate)
{
DateTime dt;
if (DateTime.TryParse(strDate, out dt))
{
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
return strDate;
}
}

不出意外,肯定是要出意外的,不然也不会有这个素材去水一篇博客了

正戏

有个字段的值是9.9,结果被序列化成了 2022-09-09 00:00:00,吃了一惊,看来是把这个数字格式化成月份日份了,真有意思,又GET到一个新姿势,发现问题解决问题就简单多了,因为定义了数据模型,我们直接在反射的时候,获取该值的类型做判断即可

public static async Task<bool> CheckSign(dynamic request, string secret)
{
SortedDictionary<string, string> dict = new SortedDictionary<string, string>();
foreach (PropertyInfo p in request.GetType().GetProperties())
{
var value = p.GetValue(request);
if (value == null)
{
dict[p.Name] = "";
}
else
{
var valueType = value.GetType();
if (valueType.Name == "DateTime")
{
dict[p.Name] = Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
dict[p.Name] = value.ToString();
}
}
}
var sign = dict["sign"];
dict.Remove("sign");
var data = "";
foreach (var item in dict)
{
data += $"{item.Key}={item.Value}&";
}
data += $"secret_key={secret}";
var new_sign = EncryptHelper.SHA1Encryption(data);
return new_sign.ToLower() == sign.ToLower();
}

尾戏

看到这里,可能就有小伙伴有话要说了,你这定义了一个模型,还要通过循环两次,才能生成待加密的明文字符串,不符合"简单",干脆直接用个有序字典去接收参数好了,这样只用循环一次

秒啊,秒啊,秒啊,妙蛙种子都没有你秒,这种做法不是不行,但是后面维护的人估计要抓狂了,按照规约,我们是不推荐这么干的,这次就破例这么干一次,抛出另一个问题,一个字符串,如何判断它是一个我们约定的时间格式,很显然9.9并不是约定的时间格式

这里推荐 DateTime.ParseExact方法,可以根据我们自定义的方式,来格式化时间,舒坦了...

public static string GetFmortDateTime(string strDate)
{
string[] format = { "yyyy-MM-ddTHH:mm:ss" };
DateTime dt;
if (DateTime.TryParseExact(strDate,format,CultureInfo.InvariantCulture,DateTimeStyles.None,out dt))
{
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
return strDate;
}
}

C#里如何简单的校验时间格式的更多相关文章

  1. java校验时间格式 HH:MM

    package com; import java.text.SimpleDateFormat; import java.util.Date; /** * @author Gerrard */ publ ...

  2. jQuery中校验时间格式的正则表达式小结

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  3. JS时间格式和时间戳的相互转换

    时间戳转化为日期的方式 ; var newDate = new Date(); newDate.setTime(timestamp * ); // Mon May 28 2018 console.lo ...

  4. MySQL解决存入数据库和取出数据库时间格式问题

    我们在往数据库里存数据时,时间格式正是我们想要的,然而取数据时去出现了这种情况 这明显不是我们想要的! 解决办法: 在我们配置mysql时添加一行代码: timezone:"08:00&qu ...

  5. Kendo Web UI Grid里时间格式转换

    我和大家分享一下我的kendo的学习心得.如果不好的地方多多包含或者给我留言请看图 kendo里时间格式如图Oder Date列里的格式.但是我们想把时间转换成中国人习惯的格式.如Shipped Da ...

  6. 时间操作(JavaScript版)—最简单比較两个时间格式数据的大小

    呵呵呵,在软件研发过程中假设遇到要比較两个时间的大小.你会怎么做.嗯嗯嗯,非常直观的做法就是把"-"去掉,再比較大小,真的有必要吗?看以下最简单的时间比較方式: <!DOCT ...

  7. 记录微信小程序里自带 时间格式 工具

    微信小程序里面自己给了一个时间工具,是用来记录log日志,感觉可以记录下来,所以拿来自己用,以此记录: 直接传入 日期对象 进入 formatTime //得到下面格式的时间格式2017/07/22 ...

  8. 使用饿了么el-date-picker里及如何将后台给的时间戳js转化为时间格式

    首先代码是这个样子的,使用v-model <el-date-picker v-model="formData.createTime" :disabled="true ...

  9. 时间格式的处理和数据填充和分页---laravel

    时间格式文档地址:http://carbon.nesbot.com/docs/ 这是些时间格式,只需要我们这么做就可以 我们在模板层,找到对应的模型对象那里进行处理就可以啦 2018-11-08 16 ...

随机推荐

  1. spring boot 统一接口异常返回值

    创建业务 Exception 一般在实际项目中,推荐创建自己的 Exception 类型,这样在后期会更容易处理,也比较方便统一,否则,可能每个人都抛出自己喜欢的异常类型,而造成代码混乱 Servic ...

  2. 渗透:zANTI

    Zanti简介 Zanti是由Zimperium公司打造的Android平台下的渗透测试工具包. Zanti支持两种中间人攻击方式,分别为MIMT攻击和ARP攻击,中间人内带有多个攻击模块,例如MAC ...

  3. vuex+Es6语法补充-Promise

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,采用 集中式存储管理 单页面的状态管理/多页面状态管理 使用步骤: // 1.导入 import Vuex from 'vuex' // ...

  4. Java基础(1)——ThreadLocal

    1. Java基础(1)--ThreadLocal 1.1. ThreadLocal ThreadLocal是一个泛型类,当我们在一个类中声明一个字段:private ThreadLocal<F ...

  5. Java实现http大文件流读取并批量插入数据库

    1.概述 请求远程大文本,使用流的方式进行返回.需要设置http链接的超时时间 循环插入到List中,使用mybatis-plus批量插入到mysql中 2.需求 两台服务器 大文件放到其中一台服务器 ...

  6. 介绍python和库文件管理

    一.Python 特点 1.易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单. 2.易于阅读:Python代码定义的更清晰. 3.易于维护:Python的成功 ...

  7. netty系列之:HashedWheelTimer一种定时器的高效实现

    目录 简介 java.util.Timer java.util.concurrent.ScheduledThreadPoolExecutor HashedWheelTimer 总结 简介 定时器是一种 ...

  8. NC50528 滑动窗口

    NC50528 滑动窗口 题目 题目描述 给一个长度为N的数组,一个长为K的滑动窗体从最左端移至最右端,你只能看到窗口中的K个数,每次窗体向右移动一位,如下图: 你的任务是找出窗体在各个位置时的最大值 ...

  9. Linux操作系统(4):磁盘分区、挂载

    Outline: ① lsblk :查看所有设备挂载情况 ② df -h :查询系统整体磁盘使用情况 ③ du -h /目录 :查询指定目录的磁盘占用情况 ④ mount :查询系统中已经挂载的设备 ...

  10. 写出个灵活的系统竟然可以如此简单!小白也能写出高级的Java业务!

    一 最近正好公司里有个需求,一个短信业务接了多个第三方供应商,某些业务需要查询第三方供应商剩余的短信包数量去选择剩余量最多的渠道去批量发送.有些业务是指定了某个短信供应商,有些场景需要根据业务的值去动 ...