Administrator
3 天以前 8bd4e49b8ffb54b8039c528f347f3996e766d8a9
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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
{
    /// <summary>
    /// 验签
    /// </summary>
    [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<object>(
                    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<string, string> filteredProperties = new Dictionary<string, string>();
            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; }
    }
 
}