1
llj
4 天以前 599aeb0d380f9b194e1dc363364779f3b498969e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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 originalContentType = actionContext.Request.Content.Headers.ContentType;
 
 
                var bodyBytes = await actionContext.Request.Content.ReadAsByteArrayAsync();
                rawData = Encoding.UTF8.GetString(bodyBytes);
 
 
                actionContext.Request.Content = new ByteArrayContent(bodyBytes);
                if (originalContentType != null)
                {
                    actionContext.Request.Content.Headers.ContentType = originalContentType;
                }
            }
            //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 + "&timestamp=" + 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();
            }
        }
    }
}