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; using Utility.Entity; using Microsoft.AspNetCore.Http; namespace Utility { /// /// 验签 /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class VerificationAttribute : ActionFilterAttribute { private string 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 system = request.Headers["System"].FirstOrDefault(); var timestamp = request.Headers["Timestamp"].FirstOrDefault(); var signature = request.Headers["Signature"].FirstOrDefault(); //var timestamp = "1718873584"; //var signature = "1718873584"; switch (system) { case "ERP": appKey = SignConfig.ERPAppKey; break; case "MES": appKey = SignConfig.MESAppKey; break; case "LIMS": appKey = SignConfig.LIMSAppKey; break; case "FuMa": appKey = SignConfig.FuMaAppKey; break; default: context.Result = new UnauthorizedResult(); return; } if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(signature)) { context.Result = new UnauthorizedResult(); return; } // 验证时间戳是否在允许的时间范围内 if (!IsTimestampValid(timestamp)) { context.Result = new UnauthorizedResult(); var apiResponse = new ApiResponse( 401, "error", "时间失效" ); var json = JsonConvert.SerializeObject(apiResponse); context.HttpContext.Response.ContentType = "application/json"; context.HttpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(json); await context.HttpContext.Response.WriteAsync(json); await base.OnActionExecutionAsync(context, next); 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 ERPAppKey { get; set; } public static string MESAppKey { get; set; } public static string LIMSAppKey { get; set; } public static string FuMaAppKey { get; set; } public static double Minutes { get; set; } } }