using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utility.Tools;
using static System.Net.Mime.MediaTypeNames;
namespace Utility
{
///
/// 验签
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class VerificationAttribute : ActionFilterAttribute
{
private static readonly string appKey = SignConfig.AppKey;
private static readonly double Minutes = SignConfig.Minutes;//时间戳必须5分钟内的,否则不通过
public VerificationAttribute()
{
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var request = context.HttpContext.Request;
// 获取请求中的时间戳和签名
var timestamp = request.Headers["Timestamp"].FirstOrDefault();
var signature = request.Headers["Signature"].FirstOrDefault();
//var timestamp = "1718873584";
//var signature = "1718873584";
if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(signature))
{
context.Result = new UnauthorizedResult();
return;
}
// 验证时间戳是否在允许的时间范围内
if (!IsTimestampValid(timestamp))
{
context.Result = new UnauthorizedResult();
return;
}
// 读取请求体中的 JSON 参数
string jsonParams;
using (var reader = new System.IO.StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
{
// 将请求体流位置重置到起始位置
request.Body.Seek(0, System.IO.SeekOrigin.Begin);
jsonParams = await reader.ReadToEndAsync();
}
// 反序列化 JSON 参数为 JObject
JObject jObject = null;
Dictionary filteredProperties = new Dictionary();
if (jsonParams != null)
{
try
{
jObject = JObject.Parse(jsonParams);
// 过滤掉数组类型的属性
filteredProperties = jObject.Properties()
.Where(p => p.Value.Type != JTokenType.Array)
.ToDictionary(p => p.Name, p => p.Value.ToString());
}
catch (JsonReaderException)
{
// JSON 格式错误,返回未经授权
context.Result = new UnauthorizedResult();
return;
}
}
filteredProperties.Add("timestamp", timestamp);
filteredProperties.Add("appKey", appKey);
// 构建待签名字符串
var signatureBaseString = string.Join("&", filteredProperties.OrderBy(p => p.Key).Select(p => p.Key + "=" + p.Value));
// 计算 MD5 值
var computedSignature = Md5Tools.CalcMd5(Encoding.UTF8.GetBytes(signatureBaseString));
// 验证签名
if (computedSignature != signature)
{
context.Result = new UnauthorizedResult();
return;
}
await base.OnActionExecutionAsync(context, next);
}
private bool IsTimestampValid(string timestamp)
{
//var logs = long.Parse(timestamp);
//var logs2 = int.Parse(timestamp);
if (long.TryParse(timestamp, out var timestampSeconds))
{
var requestDateTime = DateTimeOffset.FromUnixTimeSeconds(timestampSeconds);
var currentDateTime = DateTimeOffset.UtcNow;
// 计算时间差
var timeDifference = currentDateTime - requestDateTime;
// 比较时间差是否在允许的范围内
return timeDifference.TotalMinutes <= Minutes;
}
return false;
}
}
public class SignConfig
{
public static string AppKey { get; set; }
public static double Minutes { get; set; }
}
}