ntminer 5 years ago
parent
commit
6cf5fd165e

+ 12 - 1
src/UnitTests/ReflectionTests.cs

@@ -1,5 +1,4 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using NTMiner;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -8,6 +7,10 @@ using System.Reflection;
 namespace NTMiner {
     [TestClass]
     public class ReflectionTests {
+        public class AClass {
+            private static void MethodT<T>() { }
+        }
+
         public class Class1 {
             public string Property1 { get; set; }
             public string Property2 { get; set; }
@@ -32,6 +35,14 @@ namespace NTMiner {
             public bool BooleanProperty { get; set; }
         }
 
+        [TestMethod]
+        public void Test() {
+            foreach (var item in typeof(AClass).GetMethods()) {
+                Console.WriteLine(item.Name);
+            }
+            Console.WriteLine(typeof(AClass).GetMethod("MethodT", BindingFlags.NonPublic | BindingFlags.Static).Name);
+        }
+
         [TestMethod]
         public void OrderTest() {
             // 反射出的属性集合的顺序是和静态源代码声明的顺序一致的,但静态源代码的顺序可能会被调整,所以当基于反射的数据签名时必须考虑到排序。

+ 2 - 70
src/WebApiServer/Controllers/ApiControllerBase.cs

@@ -1,5 +1,4 @@
 using NTMiner.User;
-using System.Collections.Specialized;
 using System.ServiceModel.Channels;
 using System.Web;
 using System.Web.Http;
@@ -62,77 +61,10 @@ namespace NTMiner.Controllers {
             return ip;
         }
 
-        private ClientSignData _clientSign;
-        protected ClientSignData ClientSign {
+        protected new UserData User {
             get {
-                if (_clientSign == null) {
-                    var queryString = new NameValueCollection();
-                    string query = Request.RequestUri.Query;
-                    if (!string.IsNullOrEmpty(query)) {
-                        query = query.Substring(1);
-                        string[] parts = query.Split('&');
-                        foreach (var item in parts) {
-                            string[] pair = item.Split('=');
-                            if (pair.Length == 2) {
-                                queryString.Add(pair[0], pair[1]);
-                            }
-                        }
-                    }
-                    long timestamp = 0;
-                    string t = queryString["timestamp"];
-                    if (!string.IsNullOrEmpty(t)) {
-                        long.TryParse(t, out timestamp);
-                    }
-                    _clientSign = new ClientSignData(queryString["loginName"], queryString["sign"], timestamp);
-                }
-                return _clientSign;
-            }
-        }
-
-        protected bool IsValidAdmin<TResponse>(ISignableData data, out TResponse response, out UserData user) where TResponse : ResponseBase, new() {
-            if (IsValidUser(data, out response, out user)) {
-                if (!user.IsAdmin()) {
-                    string message = "对不起,您不是超管";
-                    response = ResponseBase.NotExist<TResponse>(message);
-                    return false;
-                }
-                else {
-                    return true;
-                }
-            }
-            else {
-                return false;
-            }
-        }
-
-        protected bool IsValidUser<TResponse>(ISignableData data, out TResponse response, out UserData user) where TResponse : ResponseBase, new() {
-            user = null;
-            if (!WebApiRoot.UserSet.IsReadied) {
-                string message = "服务器用户集启动中,请稍后";
-                response = ResponseBase.NotExist<TResponse>(message);
-                return false;
-            }
-            ClientSignData query = ClientSign;
-            if (!Timestamp.IsInTime(query.Timestamp)) {
-                response = ResponseBase.Expired<TResponse>();
-                return false;
-            }
-            if (!string.IsNullOrEmpty(query.LoginName)) {
-                user = WebApiRoot.UserSet.GetUser(query.UserId);
-            }
-            if (user == null) {
-                string message = "用户不存在";
-                response = ResponseBase.NotExist<TResponse>(message);
-                return false;
-            }
-            string mySign = RpcUser.CalcSign(user.LoginName, user.Password, query.Timestamp, data);
-            if (query.Sign != mySign) {
-                string message = "签名错误:1. 可能因为登录名或密码错误;2. 可能因为软件版本过期需要升级软件,请将软件升级到最新版本再试。";
-                response = ResponseBase.Forbidden<TResponse>(message);
-                return false;
+                return (UserData)ControllerContext.RouteData.Values["_user"];
             }
-            response = null;
-            return true;
         }
     }
 }

+ 1 - 3
src/WebApiServer/Controllers/AppSettingController.cs

@@ -19,15 +19,13 @@ namespace NTMiner.Controllers {
             return serverState.ToLine();
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase SetAppSetting([FromBody]DataRequest<AppSettingData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 VirtualRoot.Execute(new SetLocalAppSettingCommand(request.Data));
                 Logger.InfoDebugLine($"{nameof(SetAppSetting)}({request.Data.Key}, {request.Data.Value})");
                 return ResponseBase.Ok();

+ 1 - 3
src/WebApiServer/Controllers/CalcConfigController.cs

@@ -22,15 +22,13 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region SaveCalcConfigs
+        [Role.Admin]
         [HttpPost]
         public ResponseBase SaveCalcConfigs([FromBody]SaveCalcConfigsRequest request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.CalcConfigSet.SaveCalcConfigs(request.Data);
                 return ResponseBase.Ok();
             }

+ 8 - 18
src/WebApiServer/Controllers/ClientDataController.cs

@@ -1,5 +1,4 @@
 using NTMiner.Core.MinerServer;
-using NTMiner.User;
 using System;
 using System.Collections.Generic;
 using System.Web.Http;
@@ -8,17 +7,15 @@ namespace NTMiner.Controllers {
     // 注意该控制器不能重命名
     public class ClientDataController : ApiControllerBase, IClientDataController {
         #region QueryClients
+        [Role.User]
         [HttpPost]
         public QueryClientsResponse QueryClients([FromBody]QueryClientsRequest query) {
             if (query == null) {
                 return ResponseBase.InvalidInput<QueryClientsResponse>("参数错误");
             }
             try {
-                if (!IsValidUser(query, out QueryClientsResponse response, out UserData user)) {
-                    return response;
-                }
                 var data = WebApiRoot.ClientDataSet.QueryClients(
-                    user, 
+                    User, 
                     query, 
                     out int total, 
                     out List<CoinSnapshotData> latestSnapshots, 
@@ -34,17 +31,15 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region UpdateClient
+        [Role.User]
         [HttpPost]
         public ResponseBase UpdateClient([FromBody]UpdateClientRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
                 var clientData = WebApiRoot.ClientDataSet.GetByObjectId(request.ObjectId);
-                if (clientData != null && clientData.IsOwnerBy(user)) {
+                if (clientData != null && clientData.IsOwnerBy(User)) {
                     WebApiRoot.ClientDataSet.UpdateClient(request.ObjectId, request.PropertyName, request.Value);
                 }
                 return ResponseBase.Ok();
@@ -57,19 +52,17 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region UpdateClients
+        [Role.User]
         [HttpPost]
         public ResponseBase UpdateClients([FromBody]UpdateClientsRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
                 List<string> toRemoveKeys = new List<string>();
                 foreach (var key in request.Values.Keys) {
                     var minerData = WebApiRoot.ClientDataSet.GetByObjectId(key);
-                    if (minerData == null && !minerData.IsOwnerBy(user)) {
+                    if (minerData == null && !minerData.IsOwnerBy(User)) {
                         toRemoveKeys.Add(key);
                     }
                 }
@@ -87,6 +80,7 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region RemoveClients
+        [Role.User]
         [HttpPost]
         public ResponseBase RemoveClients([FromBody]MinerIdsRequest request) {
             if (request == null || request.ObjectIds == null) {
@@ -94,13 +88,9 @@ namespace NTMiner.Controllers {
             }
 
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
-
                 foreach (var objectId in request.ObjectIds) {
                     var minerData = WebApiRoot.ClientDataSet.GetByObjectId(objectId);
-                    if (minerData != null && minerData.IsOwnerBy(user)) {
+                    if (minerData != null && minerData.IsOwnerBy(User)) {
                         WebApiRoot.ClientDataSet.RemoveByObjectId(objectId);
                     }
                 }

+ 1 - 4
src/WebApiServer/Controllers/CoinSnapshotController.cs

@@ -1,5 +1,4 @@
 using NTMiner.Core.MinerServer;
-using NTMiner.User;
 using System;
 using System.Collections.Generic;
 using System.Web.Http;
@@ -7,15 +6,13 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     public class CoinSnapshotController : ApiControllerBase, ICoinSnapshotController {
         #region LatestSnapshots
+        [Role.Admin]
         [HttpPost]
         public GetCoinSnapshotsResponse LatestSnapshots([FromBody]GetCoinSnapshotsRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<GetCoinSnapshotsResponse>("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out GetCoinSnapshotsResponse response, out UserData user)) {
-                    return response;
-                }
                 List<CoinSnapshotData> data = WebApiRoot.CoinSnapshotSet.GetLatestSnapshots(
                     request.Limit,
                     out int totalMiningCount,

+ 3 - 9
src/WebApiServer/Controllers/FileUrlController.cs

@@ -7,15 +7,13 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     // 注意该控制器不能重命名
     public class FileUrlController : ApiControllerBase, IFileUrlController {
+        [Role.Admin]
         [HttpPost]
         public string MinerJsonPutUrl([FromBody]MinerJsonPutUrlRequest request) {
             if (request == null || string.IsNullOrEmpty(request.FileName)) {
                 return string.Empty;
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response.Description;
-                }
                 var req = new GeneratePresignedUriRequest("minerjson", request.FileName, SignHttpMethod.Put);
                 var uri = WebApiRoot.OssClient.GeneratePresignedUri(req);
                 return uri.ToString();
@@ -44,15 +42,13 @@ namespace NTMiner.Controllers {
             return list;
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddOrUpdateNTMinerFile([FromBody]DataRequest<NTMinerFileData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.NTMinerFileSet.AddOrUpdate(request.Data);
                 return ResponseBase.Ok();
             }
@@ -62,15 +58,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveNTMinerFile([FromBody]DataRequest<Guid> request) {
             if (request == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.NTMinerFileSet.RemoveById(request.Data);
                 return ResponseBase.Ok();
             }

+ 2 - 6
src/WebApiServer/Controllers/KernelOutputKeywordController.cs

@@ -19,15 +19,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveKernelOutputKeyword(DataRequest<Guid> request) {
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 VirtualRoot.Execute(new RemoveKernelOutputKeywordCommand(request.Data));
                 WebApiRoot.UpdateKernelOutputKeywordTimestamp(DateTime.Now);
                 return ResponseBase.Ok();
@@ -38,15 +36,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddOrUpdateKernelOutputKeyword(DataRequest<KernelOutputKeywordData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 if (request.Data.GetDataLevel() != DataLevel.Global) {
                     return ResponseBase.InvalidInput("添加到服务器的内核输出关键字记录的DataLevel属性必须赋值为Global");
                 }

+ 2 - 6
src/WebApiServer/Controllers/NTMinerWalletController.cs

@@ -6,15 +6,13 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     public class NTMinerWalletController : ApiControllerBase, INTMinerWalletController {
         #region AddOrUpdateNTMinerWallet
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddOrUpdateNTMinerWallet([FromBody]DataRequest<NTMinerWalletData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.NTMinerWalletSet.AddOrUpdate(request.Data);
                 return ResponseBase.Ok();
             }
@@ -26,15 +24,13 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region RemoveNTMinerWallet
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveNTMinerWallet([FromBody]DataRequest<Guid> request) { 
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.NTMinerWalletSet.RemoveById(request.Data);
                 return ResponseBase.Ok();
             }

+ 2 - 6
src/WebApiServer/Controllers/OverClockDataController.cs

@@ -7,15 +7,13 @@ namespace NTMiner.Controllers {
     // 注意该控制器不能重命名
     public class OverClockDataController : ApiControllerBase, IOverClockDataController {
         #region AddOrUpdateOverClockData
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddOrUpdateOverClockData([FromBody]DataRequest<OverClockData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.OverClockDataSet.AddOrUpdate(request.Data);
                 return ResponseBase.Ok();
             }
@@ -27,15 +25,13 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region RemoveOverClockData
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveOverClockData([FromBody]DataRequest<Guid> request) {
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.OverClockDataSet.RemoveById(request.Data);
                 return ResponseBase.Ok();
             }

+ 2 - 6
src/WebApiServer/Controllers/ServerMessageController.cs

@@ -19,15 +19,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddOrUpdateServerMessage([FromBody]DataRequest<ServerMessageData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 VirtualRoot.Execute(new AddOrUpdateServerMessageCommand(request.Data));
                 WebApiRoot.UpdateServerMessageTimestamp();
                 return ResponseBase.Ok();
@@ -38,15 +36,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase MarkDeleteServerMessage([FromBody]DataRequest<Guid> request) {
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 VirtualRoot.Execute(new MarkDeleteServerMessageCommand(request.Data));
                 WebApiRoot.UpdateServerMessageTimestamp();
                 return ResponseBase.Ok();

+ 2 - 6
src/WebApiServer/Controllers/UserAppSettingController.cs

@@ -6,15 +6,13 @@ using System.Web.Http;
 
 namespace NTMiner.Controllers {
     public class UserAppSettingController : ApiControllerBase, IUserAppSettingController {
+        [Role.User]
         [HttpPost]
         public DataResponse<List<UserAppSettingData>> AppSettings([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<List<UserAppSettingData>>>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out DataResponse<List<UserAppSettingData>> response, out _)) {
-                    return response;
-                }
                 var data = WebApiRoot.UserAppSettingSet;
                 return DataResponse<List<UserAppSettingData>>.Ok(data.GetAppSettings(request.Data).Select(a => UserAppSettingData.Create(a)).ToList());
             }
@@ -24,15 +22,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.User]
         [HttpPost]
         public ResponseBase SetAppSetting([FromBody]DataRequest<UserAppSettingData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.UserAppSettingSet.SetAppSetting(request.Data);
                 return ResponseBase.Ok();
             }

+ 18 - 54
src/WebApiServer/Controllers/UserController.cs

@@ -6,23 +6,18 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     public class UserController : ApiControllerBase, IUserController {
         #region Admin的操作
-        /// <summary>
-        /// 验证Admin
-        /// </summary>
+        [Role.Admin]
         [HttpPost]
         public QueryUsersResponse QueryUsers([FromBody]QueryUsersRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<QueryUsersResponse>("参数错误");
             }
-            if (!IsValidAdmin(request, out QueryUsersResponse response, out UserData user)) {
-                return response;
-            }
             try {
                 var datas = WebApiRoot.UserSet.QueryUsers(request, out int total).Select(a => a.Clone()).ToList();
                 foreach (var data in datas) {
                     // 不在网络上传输私钥原文,传输的是密文
-                    data.Password = Convert.ToBase64String(Cryptography.QuickUtil.TextEncrypt(data.Password, user.Password));
-                    data.PrivateKey = Convert.ToBase64String(Cryptography.QuickUtil.TextEncrypt(data.PrivateKey, user.Password));
+                    data.Password = Convert.ToBase64String(Cryptography.QuickUtil.TextEncrypt(data.Password, User.Password));
+                    data.PrivateKey = Convert.ToBase64String(Cryptography.QuickUtil.TextEncrypt(data.PrivateKey, User.Password));
                 }
                 return new QueryUsersResponse {
                     StateCode = 200,
@@ -37,21 +32,16 @@ namespace NTMiner.Controllers {
             }
         }
 
-        /// <summary>
-        /// 验证Admin
-        /// </summary>
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveUser([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string> response, out UserData admin)) {
-                return response;
-            }
             if (request.Data == Role.RoleEnum.admin.GetName()) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作admin");
             }
-            if (request.Data == admin.LoginName) {
+            if (request.Data == User.LoginName) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能删除自己");
             }
             try {
@@ -63,21 +53,16 @@ namespace NTMiner.Controllers {
             }
         }
 
-        /// <summary>
-        /// 验证Admin
-        /// </summary>
+        [Role.Admin]
         [HttpPost]
         public ResponseBase EnableUser([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string> response, out UserData admin)) {
-                return response;
-            }
             if (request.Data == Role.RoleEnum.admin.GetName()) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作admin");
             }
-            if (request.Data == admin.LoginName) {
+            if (request.Data == User.LoginName) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能启用自己");
             }
             try {
@@ -89,22 +74,16 @@ namespace NTMiner.Controllers {
             }
         }
 
-        /// <summary>
-        /// 验证Admin
-        /// 应在界面上告知用户被禁用的账户下的所有矿机的外网群控将掉线
-        /// </summary>
+        [Role.Admin]
         [HttpPost]
         public ResponseBase DisableUser([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string> response, out UserData admin)) {
-                return response;
-            }
             if (request.Data == Role.RoleEnum.admin.GetName()) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作admin");
             }
-            if (request.Data == admin.LoginName) {
+            if (request.Data == User.LoginName) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能禁用自己");
             }
             try {
@@ -116,19 +95,16 @@ namespace NTMiner.Controllers {
             }
         }
 
-
+        [Role.Admin]
         [HttpPost]
         public ResponseBase AddAdminRole([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string> response, out UserData admin)) {
-                return response;
-            }
             if (request.Data == Role.RoleEnum.admin.GetName()) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作admin");
             }
-            if (request.Data == admin.LoginName) {
+            if (request.Data == User.LoginName) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作自己");
             }
             try {
@@ -140,19 +116,16 @@ namespace NTMiner.Controllers {
             }
         }
 
-
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveAdminRole([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string> response, out UserData admin)) {
-                return response;
-            }
             if (request.Data == Role.RoleEnum.admin.GetName()) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作admin");
             }
-            if (request.Data == admin.LoginName) {
+            if (request.Data == User.LoginName) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("不能操作自己");
             }
             try {
@@ -166,16 +139,14 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region Login
+        [Role.User]
         [HttpPost]
         public DataResponse<LoginedUser> Login([FromBody]SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<LoginedUser>>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out DataResponse<LoginedUser> response, out UserData user)) {
-                    return response;
-                }
-                return DataResponse<LoginedUser>.Ok(user.ToLoginedUserData());
+                return DataResponse<LoginedUser>.Ok(User.ToLoginedUserData());
             }
             catch (Exception e) {
                 Logger.ErrorDebugLine(e);
@@ -244,14 +215,12 @@ namespace NTMiner.Controllers {
         /// <summary>
         /// 验证User,不具有修改密码的功能,修改密码走ChangePassword过程
         /// </summary>
+        [Role.User]
         [HttpPost]
         public ResponseBase UpdateUser([FromBody]DataRequest<UserUpdateInput> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
-            if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                return response;
-            }
             if (request.Data.ActionCaptchaId == Guid.Empty
                 || string.IsNullOrEmpty(request.Data.ActionCaptcha)
                 || !WebApiRoot.CaptchaSet.IsValid(request.Data.ActionCaptchaId, base.MinerIp, request.Data.ActionCaptcha)) {
@@ -276,9 +245,7 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region ChangePassword
-        /// <summary>
-        /// 验证User
-        /// </summary>
+        [Role.User]
         [HttpPost]
         public ResponseBase ChangePassword([FromBody]ChangePasswordRequest request) {
             if (request == null) {
@@ -287,10 +254,7 @@ namespace NTMiner.Controllers {
             if (string.IsNullOrEmpty(request.NewPassword)) {
                 return ResponseBase.InvalidInput("密码不能为空");
             }
-            if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                return response;
-            }
-            WebApiRoot.UserSet.ChangePassword(user.LoginName, request.NewPassword);
+            WebApiRoot.UserSet.ChangePassword(User.LoginName, request.NewPassword);
             return ResponseBase.Ok("密码修改成功");
         }
         #endregion

+ 12 - 24
src/WebApiServer/Controllers/UserMineWorkController.cs

@@ -9,16 +9,14 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     public class UserMineWorkController : ApiControllerBase, IUserMineWorkController {
         #region MineWorks
+        [Role.User]
         [HttpPost]
         public DataResponse<List<UserMineWorkData>> MineWorks([FromBody]SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<List<UserMineWorkData>>>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out DataResponse<List<UserMineWorkData>> response, out UserData user)) {
-                    return response;
-                }
-                var data = WebApiRoot.MineWorkSet.GetsByLoginName(user.LoginName);
+                var data = WebApiRoot.MineWorkSet.GetsByLoginName(User.LoginName);
                 return DataResponse<List<UserMineWorkData>>.Ok(data);
             }
             catch (Exception e) {
@@ -29,16 +27,14 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region AddOrUpdateMineWork
+        [Role.User]
         [HttpPost]
         public ResponseBase AddOrUpdateMineWork([FromBody]DataRequest<MineWorkData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
-                WebApiRoot.MineWorkSet.AddOrUpdate(request.Data.ToUserMineWork(user.LoginName));
+                WebApiRoot.MineWorkSet.AddOrUpdate(request.Data.ToUserMineWork(User.LoginName));
                 return ResponseBase.Ok();
             }
             catch (Exception e) {
@@ -49,20 +45,18 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region RemoveMineWork
+        [Role.User]
         [HttpPost]
         public ResponseBase RemoveMineWork([FromBody]DataRequest<Guid> request) {
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
                 IUserMineWork mineWork = WebApiRoot.MineWorkSet.GetById(request.Data);
                 if (mineWork == null) {
                     return ResponseBase.Ok();
                 }
-                if (mineWork.LoginName != user.LoginName) {
+                if (mineWork.LoginName != User.LoginName) {
                     return ResponseBase.Forbidden("无权操作");
                 }
                 if (WebApiRoot.ClientDataSet.IsAnyClientInWork(request.Data)) {
@@ -79,20 +73,18 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region ExportMineWork
+        [Role.User]
         [HttpPost]
         public ResponseBase ExportMineWork([FromBody]ExportMineWorkRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
                 IUserMineWork mineWork = WebApiRoot.MineWorkSet.GetById(request.MineWorkId);
                 if (mineWork == null) {
                     return ResponseBase.NotExist();
                 }
-                if (mineWork.LoginName != user.LoginName) {
+                if (mineWork.LoginName != User.LoginName) {
                     return ResponseBase.Forbidden("无权操作");
                 }
                 string localJsonFileFullName = SpecialPath.GetMineWorkLocalJsonFileFullName(request.MineWorkId);
@@ -109,20 +101,18 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region GetLocalJson
+        [Role.User]
         [HttpPost]
         public DataResponse<string> GetLocalJson([FromBody]DataRequest<Guid> request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<string>>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out DataResponse<string> response, out UserData user)) {
-                    return response;
-                }
                 IUserMineWork mineWork = WebApiRoot.MineWorkSet.GetById(request.Data);
                 if (mineWork == null) {
                     return ResponseBase.NotExist<DataResponse<string>>();
                 }
-                if (!user.IsAdmin() && mineWork.LoginName != user.LoginName) {
+                if (!User.IsAdmin() && mineWork.LoginName != User.LoginName) {
                     return ResponseBase.Forbidden<DataResponse<string>>("无权操作");
                 }
                 string localJsonFileFullName = SpecialPath.GetMineWorkLocalJsonFileFullName(request.Data);
@@ -139,20 +129,18 @@ namespace NTMiner.Controllers {
         }
         #endregion
 
+        [Role.User]
         [HttpPost]
         public GetWorkJsonResponse GetWorkJson([FromBody]GetWorkJsonRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<GetWorkJsonResponse>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out GetWorkJsonResponse response, out UserData user)) {
-                    return response;
-                }
                 IUserMineWork mineWork = WebApiRoot.MineWorkSet.GetById(request.WorkId);
                 if (mineWork == null) {
                     return ResponseBase.NotExist<GetWorkJsonResponse>();
                 }
-                if (!user.IsAdmin() && mineWork.LoginName != user.LoginName) {
+                if (!User.IsAdmin() && mineWork.LoginName != User.LoginName) {
                     return ResponseBase.Forbidden<GetWorkJsonResponse>("无权操作");
                 }
                 string localJsonFileFullName = SpecialPath.GetMineWorkLocalJsonFileFullName(request.WorkId);

+ 6 - 12
src/WebApiServer/Controllers/UserMinerGroupController.cs

@@ -7,16 +7,14 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     public class UserMinerGroupController : ApiControllerBase, IUserMinerGroupController {
         #region MinerGroups
+        [Role.User]
         [HttpPost]
         public DataResponse<List<UserMinerGroupData>> MinerGroups([FromBody]SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<List<UserMinerGroupData>>>("参数错误");
             }
             try {
-                if (!IsValidUser(request, out DataResponse<List<UserMinerGroupData>> response, out UserData user)) {
-                    return response;
-                }
-                var data = WebApiRoot.MinerGroupSet.GetsByLoginName(user.LoginName);
+                var data = WebApiRoot.MinerGroupSet.GetsByLoginName(User.LoginName);
                 return DataResponse<List<UserMinerGroupData>>.Ok(data);
             }
             catch (Exception e) {
@@ -27,16 +25,14 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region AddOrUpdateMinerGroup
+        [Role.User]
         [HttpPost]
         public ResponseBase AddOrUpdateMinerGroup([FromBody]DataRequest<MinerGroupData> request) {
             if (request == null || request.Data == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
-                WebApiRoot.MinerGroupSet.AddOrUpdate(request.Data.ToUserMinerGroup(user.LoginName));
+                WebApiRoot.MinerGroupSet.AddOrUpdate(request.Data.ToUserMinerGroup(User.LoginName));
                 return ResponseBase.Ok();
             }
             catch (Exception e) {
@@ -47,20 +43,18 @@ namespace NTMiner.Controllers {
         #endregion
 
         #region RemoveMinerGroup
+        [Role.User]
         [HttpPost]
         public ResponseBase RemoveMinerGroup([FromBody]DataRequest<Guid> request) {
             if (request == null || request.Data == Guid.Empty) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidUser(request, out ResponseBase response, out UserData user)) {
-                    return response;
-                }
                 IUserMinerGroup minerGroup = WebApiRoot.MinerGroupSet.GetById(request.Data);
                 if (minerGroup == null) {
                     return ResponseBase.Ok();
                 }
-                if (minerGroup.LoginName != user.LoginName) {
+                if (minerGroup.LoginName != User.LoginName) {
                     return ResponseBase.Forbidden("无权操作");
                 }
                 if (WebApiRoot.ClientDataSet.IsAnyClientInGroup(request.Data)) {

+ 1 - 3
src/WebApiServer/Controllers/WebApiServerNodeController.cs

@@ -3,15 +3,13 @@ using System.Web.Http;
 
 namespace NTMiner.Controllers {
     public class WebApiServerNodeController : ApiControllerBase, IWebApiServerNodeController {
+        [Role.Admin]
         [HttpGet]
         [HttpPost]
         public DataResponse<WebApiServerState> GetServerState(SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<WebApiServerState>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<WebApiServerState> response, out _)) {
-                return response;
-            }
             return new DataResponse<WebApiServerState> {
                 StateCode = 200,
                 ReasonPhrase = "Ok",

+ 4 - 12
src/WebApiServer/Controllers/WsServerNodeController.cs

@@ -7,14 +7,12 @@ using System.Web.Http;
 
 namespace NTMiner.Controllers {
     public class WsServerNodeController : ApiControllerBase, IWsServerNodeController {
+        [Role.Admin]
         [HttpPost]
         public DataResponse<List<WsServerNodeState>> Nodes([FromBody]SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<List<WsServerNodeState>>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<List<WsServerNodeState>> response, out _)) {
-                return response;
-            }
             return new DataResponse<List<WsServerNodeState>> {
                 StateCode = 200,
                 ReasonPhrase = "Ok",
@@ -23,14 +21,12 @@ namespace NTMiner.Controllers {
             };
         }
 
+        [Role.Admin]
         [HttpPost]
         public DataResponse<string[]> NodeAddresses([FromBody]SignRequest request) {
             if (request == null) {
                 return ResponseBase.InvalidInput<DataResponse<string[]>>("参数错误");
             }
-            if (!IsValidAdmin(request, out DataResponse<string[]> response, out _)) {
-                return response;
-            }
             return new DataResponse<string[]> {
                 StateCode = 200,
                 ReasonPhrase = "Ok",
@@ -57,15 +53,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase ReportNodeState([FromBody]WsServerNodeState state) {
             if (state == null) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(state, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.WsServerNodeSet.SetNodeState(state);
                 return ResponseBase.Ok();
             }
@@ -74,15 +68,13 @@ namespace NTMiner.Controllers {
             }
         }
 
+        [Role.Admin]
         [HttpPost]
         public ResponseBase RemoveNode([FromBody]DataRequest<string> request) {
             if (request == null || string.IsNullOrEmpty(request.Data)) {
                 return ResponseBase.InvalidInput("参数错误");
             }
             try {
-                if (!IsValidAdmin(request, out ResponseBase response, out _)) {
-                    return response;
-                }
                 WebApiRoot.WsServerNodeSet.RemoveNode(request.Data);
                 return ResponseBase.Ok();
             }

+ 14 - 0
src/WebApiServer/Role/AdminAttribute.cs

@@ -0,0 +1,14 @@
+using NTMiner.User;
+
+namespace NTMiner.Role {
+    public class AdminAttribute : UserAttribute {
+        protected override bool OnAuthorization(UserData user, out string message) {
+            if (!user.IsAdmin()) {
+                message = "对不起,您不是超管";
+                return false;
+            }
+            message = string.Empty;
+            return true;
+        }
+    }
+}

+ 99 - 0
src/WebApiServer/Role/UserAttribute.cs

@@ -0,0 +1,99 @@
+using NTMiner.User;
+using System;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Reflection;
+using System.Text;
+using System.Web.Http.Controllers;
+using System.Web.Http.Filters;
+using static NTMiner.Controllers.ApiControllerBase;
+
+namespace NTMiner.Role {
+    public class UserAttribute : ActionFilterAttribute {
+        private static readonly MethodInfo _methodInfo = typeof(UserAttribute).GetMethod(nameof(IsValidUser), BindingFlags.NonPublic | BindingFlags.Static);
+
+        protected virtual bool OnAuthorization(UserData user, out string message) {
+            message = string.Empty;
+            return true;
+        }
+
+        public override void OnActionExecuting(HttpActionContext actionContext) {
+            base.OnActionExecuting(actionContext);
+            var queryString = new NameValueCollection();
+            string query = actionContext.Request.RequestUri.Query;
+            if (!string.IsNullOrEmpty(query)) {
+                query = query.Substring(1);
+                string[] parts = query.Split('&');
+                foreach (var item in parts) {
+                    string[] pair = item.Split('=');
+                    if (pair.Length == 2) {
+                        queryString.Add(pair[0], pair[1]);
+                    }
+                }
+            }
+            long timestamp = 0;
+            string t = queryString["timestamp"];
+            if (!string.IsNullOrEmpty(t)) {
+                long.TryParse(t, out timestamp);
+            }
+            ClientSignData clientSign = new ClientSignData(queryString["loginName"], queryString["sign"], timestamp);
+            ISignableData input = null;
+            var actionParameters = actionContext.ActionDescriptor.GetParameters();
+            if (actionParameters.Count == 1 && typeof(ISignableData).IsAssignableFrom(actionParameters[0].ParameterType)) {
+                input = (ISignableData)actionContext.ActionArguments.First().Value;
+            }
+            Type returnType = actionContext.ActionDescriptor.ReturnType;
+            var tMethodInfo = _methodInfo.MakeGenericMethod(returnType);
+            string message = null;
+            var parameters = new object[] { clientSign, input, null, null };
+            bool isValid = (bool)tMethodInfo.Invoke(null, parameters);
+            ResponseBase response = (ResponseBase)parameters[2];// 因为调用的是带out参数的方法
+            UserData user = (UserData)parameters[3];// 因为调用的是带out参数的方法
+            if (isValid) {
+                isValid = OnAuthorization(user, out message);
+            }
+            if (!isValid) {
+                if (response != null && !string.IsNullOrEmpty(message)) {
+                    response.Description = message;
+                }
+                actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK) {
+                    Content = new StringContent(VirtualRoot.JsonSerializer.Serialize(response), Encoding.UTF8, "application/json")
+                };
+            }
+            else {
+                actionContext.ControllerContext.RouteData.Values["_user"] = user;
+            }
+        }
+
+        private static bool IsValidUser<TResponse>(ClientSignData query, ISignableData data, out TResponse response, out UserData user) where TResponse : ResponseBase, new() {
+            user = null;
+            if (!WebApiRoot.UserSet.IsReadied) {
+                string message = "服务器用户集启动中,请稍后";
+                response = ResponseBase.NotExist<TResponse>(message);
+                return false;
+            }
+            if (!Timestamp.IsInTime(query.Timestamp)) {
+                response = ResponseBase.Expired<TResponse>();
+                return false;
+            }
+            if (!string.IsNullOrEmpty(query.LoginName)) {
+                user = WebApiRoot.UserSet.GetUser(query.UserId);
+            }
+            if (user == null) {
+                string message = "用户不存在";
+                response = ResponseBase.NotExist<TResponse>(message);
+                return false;
+            }
+            string mySign = RpcUser.CalcSign(user.LoginName, user.Password, query.Timestamp, data);
+            if (query.Sign != mySign) {
+                string message = "签名错误:1. 可能因为登录名或密码错误;2. 可能因为软件版本过期需要升级软件,请将软件升级到最新版本再试。";
+                response = ResponseBase.Forbidden<TResponse>(message);
+                return false;
+            }
+            response = null;
+            return true;
+        }
+    }
+}

+ 2 - 0
src/WebApiServer/WebApiServer.csproj

@@ -94,6 +94,8 @@
     <Compile Include="..\MinerClientSelfHost\HttpServer.cs">
       <Link>HttpServer.cs</Link>
     </Compile>
+    <Compile Include="Role\AdminAttribute.cs" />
+    <Compile Include="Role\UserAttribute.cs" />
     <Compile Include="Controllers\ApiControllerBase.cs" />
     <Compile Include="Controllers\AppSettingController.cs" />
     <Compile Include="Controllers\CaptchaController.cs" />