kazelee
2025-07-04 3bdd686d50ae8c999924ac64101a5dbe4e271c71
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Web.Http;
 
using HH.WCS.Mobox3.DSZSH.core;
 
using Newtonsoft.Json;
 
using static HH.WCS.Mobox3.DSZSH.api.ApiModel;
using static HH.WCS.Mobox3.DSZSH.dispatch.NDC;
 
namespace HH.WCS.Mobox3.DSZSH.api {
    /// <summary>
    /// 设备信息上报(HostToAGV上报、杭奥堆垛机、国自AGV)
    /// </summary>
    [RoutePrefix("agv")]
    public class AgvController : ApiController
    {
        /// <summary>
        /// NDC HostToAGV 任务状态回报
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("AGVCallbackState")]
        public ReturnResult AGVCallbackState(AgvTaskState model){
            LogHelper.InfoHostToAGV("NDC任务状态回报", model);
            return WCSCore.OperateAgvTaskStatus(model);
        }
 
        /// <summary>
        /// AGV 与产线进行安全交互
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("SafetyInteraction")]
        public ReturnResult SafetyInteraction(SafetyInteractionInfo model) {
            LogHelper.InfoHostToAGV("AGV与产线进行安全交互", model);
            return WCSCore.SafetyInteraction(model);
        }
 
        // 备用:Request 请求授权 ---------------------------------------------
 
        // 模拟存储的AppKey和AppSecret(实际应存储在数据库或配置中)
        private static readonly Dictionary<string, string> AppSecrets = new Dictionary<string, string> {
            { "testAppKey", "7a8f9b3d2e1c6a5b4c8d7e6f" }
        };
 
        // 允许的时间差(秒),用于验证时间戳
        private const int AllowedTimeDiff = 300; // 5分钟
 
        private CheckHeadersResult CheckHeaders(System.Net.Http.Headers.HttpRequestHeaders headers) {
            // 必须字段验证
            if (!headers.Contains("AppKey") || !headers.Contains("ReqVerify") || !headers.Contains("ReqTime")) {
                return CreateCheckHeadersResult(false, HttpStatusCode.BadRequest, "缺少必要请求头参数");
            }
 
            var headerModel = new SecureRequest {
                AppKey = headers.GetValues("AppKey").First(),
                ReqVerify = headers.GetValues("ReqVerify").First(),
                ReqTime = long.Parse(headers.GetValues("ReqTime").First()),
            };
 
            // 验证Header
            var validationResult = ValidateHeaders(headerModel);
            if (validationResult != null) {
                return validationResult;
            }
 
            return CreateCheckHeadersResult(true);
        }
 
        private CheckHeadersResult ValidateHeaders(SecureRequest request) {
            // 实现所有Header验证逻辑
 
            // 验证AppKey是否存在
            if (!AppSecrets.TryGetValue(request.AppKey, out var appSecret)) {
                return CreateCheckHeadersResult(false, HttpStatusCode.Unauthorized, "无效的AppKey");
            }
 
            // 验证时间戳是否在允许范围内
            var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
            if (Math.Abs(currentTime - request.ReqTime) > AllowedTimeDiff) {
                return CreateCheckHeadersResult(false, HttpStatusCode.Unauthorized, "请求已过期");
            }
 
            // 计算验证串
            var expectedVerify = CalculateRequestVerify(request.AppKey, appSecret, request.ReqTime);
 
            // 验证请求签名
            if (!string.Equals(expectedVerify, request.ReqVerify, StringComparison.OrdinalIgnoreCase)) {
                return CreateCheckHeadersResult(false, HttpStatusCode.Unauthorized, "验证失败");
            }
 
            return null;
        }
 
        /// <summary>
        /// 构造一个成功结果的ResponseMessage
        /// </summary>
        /// <example><code><![CDATA[
        /// var res = ApiHelper.OperateAgvTaskStatus(model);
        /// return CreateSuccessResponse(res);
        /// ]]></code></example>
        /// <param name="code"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private IHttpActionResult CreateSuccessResponse(HttpStatusCode code, object data) {
            return ResponseMessage(new HttpResponseMessage(code) {
                Headers = { },
                Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")
            });
        }
 
        /// <summary>
        /// 构造一个失败结果的ResponseMessage
        /// </summary>
        /// <example><code><![CDATA[
        /// var headers = Request.Headers;
        /// var checkRes = CheckHeaders(headers);
        /// if (!checkRes.isSuccess) {
        ///     return CreateErrorResponse(checkRes.code, checkRes.message);
        /// }
        /// ]]></code></example>
        /// <param name="code"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private IHttpActionResult CreateErrorResponse(HttpStatusCode code, string message) {
            return ResponseMessage(new HttpResponseMessage(code) {
                Headers = { },
                Content = new StringContent(message)
            });
        }
 
        private CheckHeadersResult CreateCheckHeadersResult(bool isSuccess, HttpStatusCode code = HttpStatusCode.OK, string message = "") {
            return new CheckHeadersResult {
                code = code,
                message = message,
                isSuccess = isSuccess
            };
        }
 
        // 计算请求验证串
        private string CalculateRequestVerify(string appKey, string appSecret, long reqTime) {
            using (var md5 = MD5.Create()) {
                var input = $"{appKey}{appSecret}{reqTime}";
                var inputBytes = Encoding.UTF8.GetBytes(input);
                var hashBytes = md5.ComputeHash(inputBytes);
 
                // 将字节数组转换为十六进制字符串
                var sb = new StringBuilder();
                foreach (var b in hashBytes) {
                    sb.Append(b.ToString("x2"));
                }
                return sb.ToString();
            }
        }
    }
 
    // 请求模型
    public class SecureRequest {
        public string AppKey { get; set; }
        public long ReqTime { get; set; }
        public string ReqVerify { get; set; }
    }
 
    public class CheckHeadersResult {
        public bool isSuccess { get; set; }
        public HttpStatusCode code { get; set; }
        public string message { get; set; }
    }
}