using System; using System.Linq; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using WebAPI; using WebAPI.Service; namespace project.Filter { public class SignatureVerifyAttribute : AuthorizationFilterAttribute { private const string SecretKey = "MES_2026_SecretKey_XYZ!@#"; public override async System.Threading.Tasks.Task OnAuthorizationAsync( HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) { var hasAttr = actionContext.ActionDescriptor.GetCustomAttributes(true).Any() || actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes(true).Any(); if (!hasAttr) { return; } var headers = actionContext.Request.Headers; string timestamp = null, nonce = null, clientSign = null; if (headers.Contains("X-Timestamp")) timestamp = headers.GetValues("X-Timestamp").FirstOrDefault(); if (headers.Contains("X-Nonce")) nonce = headers.GetValues("X-Nonce").FirstOrDefault(); if (headers.Contains("X-Sign")) clientSign = headers.GetValues("X-Sign").FirstOrDefault(); if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(clientSign)) { actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, new { success = false, msg = "缺少签名参数(X-Timestamp/X-Nonce/X-Sign)" }); return; } double ts; if (!double.TryParse(timestamp, out ts)) { actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, new { success = false, msg = "时间戳格式错误" }); return; } var currentTs = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; var diff = Math.Abs(currentTs - ts); if (diff > 300) // 300秒 = 5分钟 { actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, new { success = false, msg = "请求已过期" }); return; } string rawData = ""; if (actionContext.Request.Method == HttpMethod.Get) { var query = actionContext.Request.RequestUri.Query; if (!string.IsNullOrEmpty(query) && query.StartsWith("?")) { rawData = query.Substring(1); } } else { var bodyBytes = await actionContext.Request.Content.ReadAsByteArrayAsync(); rawData = Encoding.UTF8.GetString(bodyBytes); actionContext.Request.Content = new ByteArrayContent(bodyBytes); if (actionContext.Request.Content.Headers.ContentType != null) { actionContext.Request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue( actionContext.Request.Content.Headers.ContentType.MediaType); } } var signStr = rawData + "×tamp=" + timestamp + "&nonce=" + nonce + "&key=" + SecretKey; var serverSign = ComputeHmacSha256(signStr, SecretKey); if (serverSign != clientSign.ToUpper()) { actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Unauthorized, new { success = false, msg = "签名验证失败" }); return; } } private string ComputeHmacSha256(string data, string key) { var keyBytes = Encoding.UTF8.GetBytes(key); var dataBytes = Encoding.UTF8.GetBytes(data); using (var hmac = new HMACSHA256(keyBytes)) { var hashBytes = hmac.ComputeHash(dataBytes); return BitConverter.ToString(hashBytes).Replace("-", "").ToUpper(); } } } }