hwh
2024-06-21 158a01ee5fa6903111790c52bfb778f93f797028
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
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
{
    /// <summary>
    /// 验签
    /// </summary>
    [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;
            try
            {
                jObject = JObject.Parse(jsonParams);
            }
            catch (JsonReaderException)
            {
                // JSON 格式错误,返回未经授权
                context.Result = new UnauthorizedResult();
                return;
            }
            // 过滤掉数组类型的属性
            var filteredProperties = jObject.Properties()
                .Where(p => p.Value.Type != JTokenType.Array)
                .ToDictionary(p => p.Name, p => p.Value.ToString());
            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; }
    }
 
}