| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- using System.Reflection;
- using Admin.NET.Core;
- using Admin.NET.Plugin.AiDOP.Controllers;
- using Admin.NET.Plugin.AiDOP.Controllers.S8;
- using Admin.NET.Plugin.AiDOP.FinishedWarehouse;
- using Admin.NET.Plugin.AiDOP.Infrastructure;
- using Admin.NET.Plugin.AiDOP.Infrastructure.S8;
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse;
- using Admin.NET.Plugin.AiDOP.Order;
- using Admin.NET.Plugin.AiDOP.Production;
- using Admin.NET.Plugin.ApprovalFlow.Service;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.Security;
- /// <summary>App 业务 API 必须复用 PC 菜单 path 权限,且保留既有业务内层守卫。</summary>
- public class AppApiPcMenuGuardTests
- {
- private const string ApprovalCenter = "/aidop/flowManage/approvalFlowCenter";
- [Fact]
- public void ApprovalAppEndpoints_RequireApprovalCenterMenu()
- {
- AssertMethodsGuarded(typeof(FlowTaskService), ApprovalCenter,
- "MyPendingPage", "MyDonePage", "MyInitiatedPage", "MyPendingCount",
- "Approve", "Reject", "Transfer", "Withdraw", "ReturnToPrev", "AddSign",
- "Urge", "BatchApprove", "BatchReject");
- AssertMethodsGuarded(typeof(FlowInstanceService), ApprovalCenter, "GetDetail", "GetTimeline");
- AssertMethodsGuarded(typeof(ApprovalFlowService), ApprovalCenter, "GetBizTypes");
- }
- [Fact]
- public void AidopQueryEndpoints_RequireCorrespondingPcMenus()
- {
- Assert.NotNull(typeof(AidopKanbanController).GetMethod("GetDashboardPage")!
- .GetCustomAttribute<RequireSmartOpsModuleMenuAttribute>());
- AssertMethodsGuarded(typeof(AidopKanbanController), "/aidop/smart-ops/s1",
- "GetSmartOpsFilterOptions");
- AssertMethodsGuarded(typeof(StockQueryService), "/aidop/s5/inventory/stock-query",
- "GetList", "GetTypeOptions", "GetLocationOptions");
- AssertMethodsGuarded(typeof(WorkOrderProgressDashboardService),
- "/aidop/s2/collaboration-kanban/work-order-progress", "GetList");
- AssertMethodsGuarded(typeof(OrderDeliveryService), "/aidop/s1/order-mgmt/orderDelivery",
- "GetDeliveryList", "GetDeliveryFlow");
- AssertMethodsGuarded(typeof(FqcInspBillService), "/aidop/s7/fqc/task-list", "GetTaskList");
- AssertMethodsGuarded(typeof(FqcInspBillService), "/aidop/s7/fqc/result-list", "GetResultList");
- AssertMethodsGuarded(typeof(FqcInspBillService), "/aidop/s7/fqc/result-detail", "GetDetail");
- }
- [Fact]
- public void S8AppEndpoints_RequirePcMenuAndKeepSecondLayer()
- {
- AssertClassGuarded(typeof(AdoS8DashboardController), "/aidop/s8/dashboard");
- AssertClassGuarded(typeof(AdoS8ExceptionsController), "/aidop/s8/exceptions");
- AssertClassGuarded(typeof(AdoS8MasterDataController), "/aidop/s8/exceptions");
- AssertMethodsGuarded(typeof(AdoS8ConfigActionPermissionController),
- "/aidop/s8/exceptions", "MineAsync");
- Assert.NotNull(typeof(AdoS8DashboardController).GetMethod("OverviewAsync")!
- .GetCustomAttribute<S8PermissionAttribute>());
- Assert.NotNull(typeof(AdoS8ExceptionsController).GetMethod("ClaimAsync")!
- .GetCustomAttribute<S8ExceptionActionAttribute>());
- }
- [Fact]
- public void ApprovalTaskOwnershipGuard_RemainsInEngine()
- {
- var source = ReadRepoFile("server", "Plugins", "Admin.NET.Plugin.ApprovalFlow",
- "Service", "FlowEngine", "FlowEngineService.cs");
- Assert.Contains("task.AssigneeId != _userManager.UserId", source);
- Assert.Contains("当前用户不是该任务的审批人", source);
- }
- [Fact]
- public void AidopTenantHelper_DoesNotTrustRequestTenantId()
- {
- var source = ReadRepoFile("server", "Plugins", "Admin.NET.Plugin.AiDOP",
- "Infrastructure", "AidopTenantHelper.cs");
- Assert.Contains("AidopTenantScope.ResolveOrThrow", source);
- Assert.DoesNotContain("Request.Query", source);
- Assert.DoesNotContain("return requestTenantId", source);
- Assert.DoesNotContain("SqlSugarConst.DefaultTenantId", source);
- }
- private static void AssertClassGuarded(Type type, string expectedPath)
- {
- var paths = type.GetCustomAttributes<RequirePcMenuPathAttribute>(true)
- .Select(x => x.MenuPath);
- Assert.Contains(expectedPath, paths);
- }
- private static void AssertMethodsGuarded(Type type, string expectedPath, params string[] methodNames)
- {
- foreach (var methodName in methodNames)
- {
- var method = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
- .SingleOrDefault(x => x.Name == methodName);
- Assert.NotNull(method);
- var paths = method!.GetCustomAttributes<RequirePcMenuPathAttribute>(true)
- .Select(x => x.MenuPath);
- Assert.Contains(expectedPath, paths);
- }
- }
- private static string ReadRepoFile(params string[] parts)
- {
- var dir = new DirectoryInfo(AppContext.BaseDirectory);
- while (dir != null && !Directory.Exists(Path.Combine(dir.FullName, "server")))
- dir = dir.Parent;
- Assert.NotNull(dir);
- return File.ReadAllText(Path.Combine(new[] { dir!.FullName }.Concat(parts).ToArray()));
- }
- }
|