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<RequireSignatureAttribute>(true).Any()
|
|| actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<RequireSignatureAttribute>(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);
|
}
|
}
|
rawData = rawData.Replace("'", "%27");
|
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();
|
}
|
}
|
}
|
}
|