diff --git a/Directory.Build.targets b/Directory.Build.targets
index 095b29a..bfc132b 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,6 +1,6 @@
- 2.0.0-preview.1.2411120955
+ 2.0.0-preview.1.2411260738
8.0.10
8.0.0
8.0.0
diff --git a/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs b/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs
deleted file mode 100644
index 91d0949..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Security.Claims;
-using Microsoft.AspNetCore.Authorization;
-using NetCorePal.D3Shop.Admin.Shared.Const;
-
-namespace NetCorePal.D3Shop.Admin.Shared.Authorization
-{
- public class PermissionAuthorizationHandler(IPermissionChecker permissionChecker)
- : AuthorizationHandler
- {
- protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
- PermissionRequirement requirement)
- {
- if (context.User.Identity?.IsAuthenticated is null or false)
- {
- context.Fail();
- return;
- }
-
- //超级管理员
- if (context.User.Claims.Any(
- claim => claim is { Type: ClaimTypes.Role, Value: AppClaim.SuperAdminRole }))
- {
- context.Succeed(requirement);
- return;
- }
-
- // 检查用户是否拥有指定权限
- var hasPermission =
- await permissionChecker.HasPermissionAsync(context.User, requirement.PermissionCode);
- if (hasPermission)
- {
- context.Succeed(requirement);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj b/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj
deleted file mode 100644
index 0369f05..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs
deleted file mode 100644
index defc4b2..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record AdminUserQueryRequest(string? Name, string? Phone);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserRefreshTokenRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserRefreshTokenRequest.cs
deleted file mode 100644
index 44101fc..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserRefreshTokenRequest.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record AdminUserRefreshTokenRequest(string Token, string RefreshToken);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs
deleted file mode 100644
index d998259..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
-
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record CreateAdminUserRequest(string Name, string Phone, string PassWord, IEnumerable RoleIds);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs
deleted file mode 100644
index 6cade62..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record CreateRoleRequest(string Name, string Description, IEnumerable PermissionCodes);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs
deleted file mode 100644
index 6fa9e94..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record RoleQueryRequest(string? Name, string? Description);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs b/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs
deleted file mode 100644
index c16f721..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Requests;
-
-public record UpdateRoleInfoRequest(string Name, string Description);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs b/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs
deleted file mode 100644
index 3d400ed..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
-
-namespace NetCorePal.D3Shop.Admin.Shared.Responses;
-
-public record AdminUserResponse(AdminUserId Id, string Name, string Phone, IEnumerable Roles, IEnumerable Permissions);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserTokenResponse.cs b/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserTokenResponse.cs
deleted file mode 100644
index db7dea4..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserTokenResponse.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Responses;
-
-public record AdminUserTokenResponse(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime);
diff --git a/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs b/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs
deleted file mode 100644
index d1b718d..0000000
--- a/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace NetCorePal.D3Shop.Admin.Shared.Responses;
-
-public record RolePermissionResponse(string PermissionCode, string Remark, string GroupName, bool IsAssigned);
\ No newline at end of file
diff --git a/d3shop.sln b/d3shop.sln
index 53b3d3a..8323bc1 100644
--- a/d3shop.sln
+++ b/d3shop.sln
@@ -31,7 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D8FA34CE-25D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCorePal.D3Shop.Web.Admin.Client", "src\NetCorePal.D3Shop.Web.Admin.Client\NetCorePal.D3Shop.Web.Admin.Client.csproj", "{45DFEB02-2164-4CF1-A17B-DCA18F763B72}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.D3Shop.Admin.Shared", "NetCorePal.D3Shop.Admin.Shared\NetCorePal.D3Shop.Admin.Shared.csproj", "{7716047C-5C31-44CF-A297-094E4956ABA0}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.D3Shop.Admin.Shared", "src\NetCorePal.D3Shop.Admin.Shared\NetCorePal.D3Shop.Admin.Shared.csproj", "{2F4BC49A-B73A-46D7-9418-3708C6E3A341}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -67,10 +67,10 @@ Global
{45DFEB02-2164-4CF1-A17B-DCA18F763B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45DFEB02-2164-4CF1-A17B-DCA18F763B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45DFEB02-2164-4CF1-A17B-DCA18F763B72}.Release|Any CPU.Build.0 = Release|Any CPU
- {7716047C-5C31-44CF-A297-094E4956ABA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7716047C-5C31-44CF-A297-094E4956ABA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7716047C-5C31-44CF-A297-094E4956ABA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7716047C-5C31-44CF-A297-094E4956ABA0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2F4BC49A-B73A-46D7-9418-3708C6E3A341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2F4BC49A-B73A-46D7-9418-3708C6E3A341}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F4BC49A-B73A-46D7-9418-3708C6E3A341}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2F4BC49A-B73A-46D7-9418-3708C6E3A341}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -83,7 +83,7 @@ Global
{0AB6D561-D07F-4833-BB91-D87EFC8485C4} = {5C6B3693-7A37-4ABF-A217-8EDA0B51F742}
{64AD4028-B7DA-4858-964D-26977C1A5EA9} = {5C6B3693-7A37-4ABF-A217-8EDA0B51F742}
{45DFEB02-2164-4CF1-A17B-DCA18F763B72} = {D8FA34CE-25DA-4E6F-AD50-1EAD1F33F9F1}
- {7716047C-5C31-44CF-A297-094E4956ABA0} = {D8FA34CE-25DA-4E6F-AD50-1EAD1F33F9F1}
+ {2F4BC49A-B73A-46D7-9418-3708C6E3A341} = {D8FA34CE-25DA-4E6F-AD50-1EAD1F33F9F1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E6FD5C45-63B8-458D-8CFA-7ACFD729624C}
diff --git a/NetCorePal.D3Shop.Admin.Shared/Authorization/IPermissionChecker.cs b/src/NetCorePal.D3Shop.Admin.Shared/Authorization/IPermissionChecker.cs
similarity index 100%
rename from NetCorePal.D3Shop.Admin.Shared/Authorization/IPermissionChecker.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Authorization/IPermissionChecker.cs
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs b/src/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs
new file mode 100644
index 0000000..aee6ce2
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionAuthorizationHandler.cs
@@ -0,0 +1,35 @@
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authorization;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Authorization;
+
+public class PermissionAuthorizationHandler(IPermissionChecker permissionChecker)
+ : AuthorizationHandler
+{
+ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
+ PermissionRequirement requirement)
+ {
+ if (context.User.Identity?.IsAuthenticated is null or false)
+ {
+ context.Fail();
+ return;
+ }
+
+ // 系统默认用户不校验权限
+ var name = context.User.Claims.Single(c => c.Type == ClaimTypes.Name).Value;
+ if (name == AppDefaultCredentials.Name)
+ {
+ context.Succeed(requirement);
+ return;
+ }
+
+ // 检查用户是否拥有指定权限
+ var hasPermission =
+ await permissionChecker.HasPermissionAsync(context.User, requirement.PermissionCode);
+ if (hasPermission)
+ {
+ context.Succeed(requirement);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionRequirement.cs b/src/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionRequirement.cs
similarity index 100%
rename from NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionRequirement.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Authorization/PermissionRequirement.cs
diff --git a/NetCorePal.D3Shop.Admin.Shared/Const/AppClaim.cs b/src/NetCorePal.D3Shop.Admin.Shared/Const/AppClaim.cs
similarity index 100%
rename from NetCorePal.D3Shop.Admin.Shared/Const/AppClaim.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Const/AppClaim.cs
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj b/src/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj
new file mode 100644
index 0000000..335f1a5
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/NetCorePal.D3Shop.Admin.Shared.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserLoginRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserLoginRequest.cs
similarity index 100%
rename from NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserLoginRequest.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserLoginRequest.cs
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs
new file mode 100644
index 0000000..ecb3e90
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Requests/AdminUserQueryRequest.cs
@@ -0,0 +1,9 @@
+using NetCorePal.Extensions.Dto;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Requests;
+
+public class AdminUserQueryRequest : PageRequest
+{
+ public string? Name { get; set; }
+ public string? Phone { get; set; }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs
new file mode 100644
index 0000000..8439230
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateAdminUserRequest.cs
@@ -0,0 +1,12 @@
+using System.ComponentModel.DataAnnotations;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Requests;
+
+public class CreateAdminUserRequest
+{
+ [Required] public string Name { get; set; } = string.Empty;
+ [Required] public string Phone { get; set; } = string.Empty;
+ [Required] public string PassWord { get; set; } = string.Empty;
+ public IEnumerable RoleIds { get; set; } = [];
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs
new file mode 100644
index 0000000..b5ca86c
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Requests/CreateRoleRequest.cs
@@ -0,0 +1,10 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Requests;
+
+public class CreateRoleRequest
+{
+ [Required] public string Name { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public IEnumerable PermissionCodes { get; set; } = [];
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs
new file mode 100644
index 0000000..924855e
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Requests/RoleQueryRequest.cs
@@ -0,0 +1,9 @@
+using NetCorePal.Extensions.Dto;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Requests;
+
+public class RoleQueryRequest : PageRequest
+{
+ public string? Name { get; set; }
+ public string? Description { get; set; }
+}
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateAdminUserPasswordRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateAdminUserPasswordRequest.cs
similarity index 100%
rename from NetCorePal.D3Shop.Admin.Shared/Requests/UpdateAdminUserPasswordRequest.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateAdminUserPasswordRequest.cs
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs b/src/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs
new file mode 100644
index 0000000..c2853ff
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Requests/UpdateRoleInfoRequest.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Requests;
+
+public class UpdateRoleInfoRequest
+{
+ [Required] public string Name { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserPermissionResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserPermissionResponse.cs
new file mode 100644
index 0000000..571a990
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserPermissionResponse.cs
@@ -0,0 +1,8 @@
+namespace NetCorePal.D3Shop.Admin.Shared.Responses;
+
+public record AdminUserPermissionResponse(
+ string Code,
+ string GroupName,
+ string Remark,
+ bool IsAssigned,
+ bool IsFromRole);
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs
new file mode 100644
index 0000000..bb61d95
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserResponse.cs
@@ -0,0 +1,10 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Responses;
+
+public class AdminUserResponse(AdminUserId id, string name, string phone)
+{
+ public AdminUserId Id { get; } = id;
+ public string Name { get; set; } = name;
+ public string Phone { get; set; } = phone;
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRoleResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRoleResponse.cs
new file mode 100644
index 0000000..607a7bb
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRoleResponse.cs
@@ -0,0 +1,10 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+
+namespace NetCorePal.D3Shop.Admin.Shared.Responses;
+
+public class AdminUserRoleResponse(RoleId roleId, string roleName, bool isAssigned)
+{
+ public RoleId RoleId { get; } = roleId;
+ public string RoleName { get; } = roleName;
+ public bool IsAssigned { get; set; } = isAssigned;
+};
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRolesResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleNameResponse.cs
similarity index 54%
rename from NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRolesResponse.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleNameResponse.cs
index 9f2e73a..d466b19 100644
--- a/NetCorePal.D3Shop.Admin.Shared/Responses/AdminUserRolesResponse.cs
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleNameResponse.cs
@@ -2,4 +2,4 @@
namespace NetCorePal.D3Shop.Admin.Shared.Responses;
-public record AdminUserRolesResponse(RoleId RoleId, string RoleName, string Description, bool IsAssigned);
\ No newline at end of file
+public record RoleNameResponse(RoleId Id, string Name);
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs
new file mode 100644
index 0000000..3c14713
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RolePermissionResponse.cs
@@ -0,0 +1,7 @@
+namespace NetCorePal.D3Shop.Admin.Shared.Responses;
+
+public record RolePermissionResponse(
+ string Code,
+ string GroupName,
+ string Remark,
+ bool IsAssigned);
\ No newline at end of file
diff --git a/NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs
similarity index 73%
rename from NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs
rename to src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs
index 97513cb..f0570a6 100644
--- a/NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs
+++ b/src/NetCorePal.D3Shop.Admin.Shared/Responses/RoleResponse.cs
@@ -2,10 +2,9 @@
namespace NetCorePal.D3Shop.Admin.Shared.Responses;
-public class RoleResponse(RoleId id, string name, string description, IEnumerable permissionCodes)
+public class RoleResponse(RoleId id, string name, string description)
{
public RoleId Id { get; } = id;
public string Name { get; set; } = name;
public string Description { get; set; } = description;
- public IEnumerable PermissionCodes { get; set; } = permissionCodes;
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/AdminUserAggregate/AdminUser.cs b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/AdminUserAggregate/AdminUser.cs
index 0702fbc..47d5f9f 100644
--- a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/AdminUserAggregate/AdminUser.cs
+++ b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/AdminUserAggregate/AdminUser.cs
@@ -77,11 +77,11 @@ public void UpdateRolePermissions(RoleId roleId, IEnumerable
- p.SourceRoleIds.Remove(roleId) && p.SourceRoleIds.Count == 0).ToArray();
-
- foreach (var permission in permissionsToRemove)
- Permissions.Remove(permission);
+ foreach (var permission in Permissions.Where(p => p.SourceRoleIds.Remove(roleId)).ToArray())
+ {
+ if (permission.SourceRoleIds.Count == 0)
+ Permissions.Remove(permission);
+ }
}
private void AddRolePermissions(RoleId roleId, IEnumerable permissions)
@@ -92,8 +92,9 @@ private void AddRolePermissions(RoleId roleId, IEnumerable
if (existingPermission is null)
{
- permission.AddSourceRoleId(roleId);
- Permissions.Add(permission);
+ var newPermission = new AdminUserPermission(permission.PermissionCode,permission.PermissionRemark);
+ newPermission.AddSourceRoleId(roleId);
+ Permissions.Add(newPermission);
}
else
{
diff --git a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/Permission.cs b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/Permission.cs
index e227bdc..1a94832 100644
--- a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/Permission.cs
+++ b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/Permission.cs
@@ -7,48 +7,55 @@ public record Permission(string Code, string GroupName, string Remark);
public static class Permissions
{
private static readonly Permission[] All =
- [
- #region AdminUserManagement
- new (PermissionDefinitions.AdminUserCreate,
- PermissionGroup.SystemAccess,
- "创建管理员用户"),
- new (PermissionDefinitions.AdminUserEdit,
- PermissionGroup.SystemAccess,
- "更新管理员用户信息"),
- new (PermissionDefinitions.AdminUserDelete,
- PermissionGroup.SystemAccess,
- "删除管理员用户"),
- new (PermissionDefinitions.AdminUserView,
- PermissionGroup.SystemAccess,
- "查询管理员用户"),
- new (PermissionDefinitions.AdminUserUpdateRoles,
- PermissionGroup.SystemAccess,
- "更新管理员用户角色"),
- new (PermissionDefinitions.AdminUserUpdatePassword,
- PermissionGroup.SystemAccess,
- "更新管理员用户密码"),
- #endregion
-
- #region RoleManagement
- new (PermissionDefinitions.RoleCreate,
- PermissionGroup.SystemAccess,
- "创建角色"),
- new (PermissionDefinitions.RoleEdit,
- PermissionGroup.SystemAccess,
- "更新角色信息"),
- new (PermissionDefinitions.RoleUpdatePermissions,
- PermissionGroup.SystemAccess,
- "更新角色权限"),
- new (PermissionDefinitions.RoleView,
- PermissionGroup.SystemAccess,
- "查询角色"),
- new (PermissionDefinitions.RoleDelete,
- PermissionGroup.SystemAccess,
- "删除角色"),
- #endregion
- ];
+ [
+ #region AdminUserManagement
+
+ new(PermissionDefinitions.AdminUserCreate,
+ PermissionGroup.SystemAccess,
+ "创建管理员用户"),
+ new(PermissionDefinitions.AdminUserEdit,
+ PermissionGroup.SystemAccess,
+ "更新管理员用户信息"),
+ new(PermissionDefinitions.AdminUserDelete,
+ PermissionGroup.SystemAccess,
+ "删除管理员用户"),
+ new(PermissionDefinitions.AdminUserView,
+ PermissionGroup.SystemAccess,
+ "查询管理员用户"),
+ new(PermissionDefinitions.AdminUserUpdateRoles,
+ PermissionGroup.SystemAccess,
+ "更新管理员用户角色"),
+ new(PermissionDefinitions.AdminUserUpdatePassword,
+ PermissionGroup.SystemAccess,
+ "更新管理员用户密码"),
+ new(PermissionDefinitions.AdminUserSetPermissions,
+ PermissionGroup.SystemAccess,
+ "配置管理员用户权限"),
+
+ #endregion
+
+ #region RoleManagement
+
+ new(PermissionDefinitions.RoleCreate,
+ PermissionGroup.SystemAccess,
+ "创建角色"),
+ new(PermissionDefinitions.RoleEdit,
+ PermissionGroup.SystemAccess,
+ "更新角色信息"),
+ new(PermissionDefinitions.RoleUpdatePermissions,
+ PermissionGroup.SystemAccess,
+ "更新角色权限"),
+ new(PermissionDefinitions.RoleView,
+ PermissionGroup.SystemAccess,
+ "查询角色"),
+ new(PermissionDefinitions.RoleDelete,
+ PermissionGroup.SystemAccess,
+ "删除角色"),
+
+ #endregion
+ ];
public static IReadOnlyList AllPermissions { get; } =
new ReadOnlyCollection(All);
}
-}
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/PermissionDefinitions.cs b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/PermissionDefinitions.cs
index 0f5f8c0..182f4c7 100644
--- a/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/PermissionDefinitions.cs
+++ b/src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/Permission/PermissionDefinitions.cs
@@ -6,6 +6,7 @@ public static class PermissionDefinitions
public const string AdminUserCreate = nameof(AdminUserCreate);
public const string AdminUserEdit = nameof(AdminUserEdit);
public const string AdminUserUpdateRoles = nameof(AdminUserUpdateRoles);
+ public const string AdminUserSetPermissions = nameof(AdminUserSetPermissions);
public const string AdminUserView = nameof(AdminUserView);
public const string AdminUserUpdatePassword = nameof(AdminUserUpdatePassword);
public const string AdminUserDelete = nameof(AdminUserDelete);
diff --git a/src/NetCorePal.D3Shop.Infrastructure/EntityConfigurations/Identity/AdminUserConfiguration.cs b/src/NetCorePal.D3Shop.Infrastructure/EntityConfigurations/Identity/AdminUserConfiguration.cs
index bbb4462..2bf434e 100644
--- a/src/NetCorePal.D3Shop.Infrastructure/EntityConfigurations/Identity/AdminUserConfiguration.cs
+++ b/src/NetCorePal.D3Shop.Infrastructure/EntityConfigurations/Identity/AdminUserConfiguration.cs
@@ -17,15 +17,15 @@ public void Configure(EntityTypeBuilder builder)
// 配置 AdminUser 与 AdminUserRole 的一对多关系
builder.HasMany(au => au.Roles)
.WithOne()
- .HasForeignKey(aur => aur.AdminUserId);
- //.OnDelete(DeleteBehavior.Cascade); // 当删除用户时,级联删除角色关联
+ .HasForeignKey(aur => aur.AdminUserId)
+ .OnDelete(DeleteBehavior.ClientCascade);
builder.Navigation(au => au.Roles).AutoInclude();
// 配置 AdminUser 与 AdminUserPermission 的一对多关系
builder.HasMany(au => au.Permissions)
.WithOne()
- .HasForeignKey(aup => aup.AdminUserId);
- //.OnDelete(DeleteBehavior.Cascade); // 当删除用户时,级联删除权限关联
+ .HasForeignKey(aup => aup.AdminUserId)
+ .OnDelete(DeleteBehavior.ClientCascade);
builder.Navigation(au => au.Permissions).AutoInclude();
builder.HasQueryFilter(au => !au.IsDeleted);
@@ -38,7 +38,6 @@ public void Configure(EntityTypeBuilder builder)
{
builder.ToTable("adminUserRoles");
builder.HasKey(aur => new { aur.AdminUserId, aur.RoleId });
- builder.HasOne().WithMany().HasForeignKey(aur => aur.RoleId);
}
}
@@ -48,7 +47,8 @@ public void Configure(EntityTypeBuilder builder)
{
builder.ToTable("adminUserPermissions");
builder.HasKey(aup => new { aup.AdminUserId, aup.PermissionCode });
- builder.Property(p => p.SourceRoleIds).HasConversion(v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
+ builder.Property(p => p.SourceRoleIds).HasConversion(
+ v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize>(v, (JsonSerializerOptions?)null) ??
new List(),
new ValueComparer>(
@@ -57,4 +57,4 @@ public void Configure(EntityTypeBuilder builder)
c => c.ToList()));
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Attributes/RefitServiceAttribute.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Attributes/RefitServiceAttribute.cs
new file mode 100644
index 0000000..bee8779
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Attributes/RefitServiceAttribute.cs
@@ -0,0 +1,4 @@
+namespace NetCorePal.D3Shop.Web.Admin.Client.Attributes;
+
+[AttributeUsage(AttributeTargets.Interface)]
+public class RefitServiceAttribute : Attribute;
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PermissionPolicyProvider.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/ClientPermissionPolicyProvider.cs
similarity index 84%
rename from src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PermissionPolicyProvider.cs
rename to src/NetCorePal.D3Shop.Web.Admin.Client/Auth/ClientPermissionPolicyProvider.cs
index e14c61e..07e99c7 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PermissionPolicyProvider.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/ClientPermissionPolicyProvider.cs
@@ -5,7 +5,7 @@
namespace NetCorePal.D3Shop.Web.Admin.Client.Auth
{
- public class PermissionPolicyProvider(IOptions options) : DefaultAuthorizationPolicyProvider(options)
+ public class ClientPermissionPolicyProvider(IOptions options) : DefaultAuthorizationPolicyProvider(options)
{
public override Task GetPolicyAsync(string policyName)
{
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PersistentAuthenticationStateProvider.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PersistentAuthenticationStateProvider.cs
index cb26d3a..cecfe25 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PersistentAuthenticationStateProvider.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Auth/PersistentAuthenticationStateProvider.cs
@@ -30,7 +30,7 @@ public PersistentAuthenticationStateProvider(PersistentComponentState state)
Claim[] claims =
[
new(ClaimTypes.NameIdentifier, userInfo.UserId),
- ..userInfo.Roles.Select(r => new Claim(ClaimTypes.Role, r)),
+ new(ClaimTypes.Name, userInfo.Name),
..userInfo.Permissions.Select(p => new Claim(AppClaim.AdminPermission, p)),
];
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/AddRole.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/AddRole.razor
similarity index 100%
rename from src/NetCorePal.D3Shop.Web.Admin.Client/Components/AddRole.razor
rename to src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/AddRole.razor
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/AddRole.razor.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/AddRole.razor.cs
similarity index 61%
rename from src/NetCorePal.D3Shop.Web.Admin.Client/Components/AddRole.razor.cs
rename to src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/AddRole.razor.cs
index 751b6e3..84fe8fa 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/AddRole.razor.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/AddRole.razor.cs
@@ -1,29 +1,23 @@
-using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Forms;
-using NetCorePal.D3Shop.Admin.Shared.Requests;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission;
-using NetCorePal.D3Shop.Web.Admin.Client.Models;
-using NetCorePal.D3Shop.Web.Admin.Client.Services;
+using Microsoft.AspNetCore.Components.Forms;
-namespace NetCorePal.D3Shop.Web.Admin.Client.Components;
+namespace NetCorePal.D3Shop.Web.Admin.Client.Components.Role;
public partial class AddRole
{
[Inject] private IRolesService RolesService { get; set; } = default!;
- [Inject] private IPermissionsService PermissionsService { get; set; } = default!;
[Inject] private MessageService Message { get; set; } = default!;
[Parameter] public EventCallback OnItemAdded { get; set; }
- private List _allPermissions = [];
+ private List _allPermissions = [];
private bool _modalVisible;
private bool _modalConfirmLoading;
- private Form _form = default!;
+ private Form _form = default!;
private Tabs _tabs = default!;
private string[] _treeCheckedKeys = [];
- private CreateRoleModel _newRoleModel = new();
+ private CreateRoleRequest _newRoleModel = new();
private async Task ShowModal()
{
@@ -31,9 +25,9 @@ private async Task ShowModal()
_allPermissions = await GetAllPermissions();
}
- private async Task> GetAllPermissions()
+ private async Task> GetAllPermissions()
{
- var response = await PermissionsService.GetAll();
+ var response = await RolesService.GetAllPermissionsForCreateRole();
if (response.Success) return response.Data.ToList();
_ = Message.Error(response.Message);
return [];
@@ -42,7 +36,7 @@ private async Task> GetAllPermissions()
private void CloseModal()
{
_modalVisible = false;
- _newRoleModel = new CreateRoleModel();
+ _newRoleModel = new CreateRoleRequest();
_treeCheckedKeys = [];
_tabs.GoTo(0);
}
@@ -51,9 +45,7 @@ private async Task Form_OnFinish(EditContext editContext)
{
_modalConfirmLoading = true;
StateHasChanged();
- var request =
- new CreateRoleRequest(_newRoleModel.Name, _newRoleModel.Description, _newRoleModel.PermissionCodes);
- var response = await RolesService.CreateRole(request);
+ var response = await RolesService.CreateRole(_newRoleModel);
if (response.Success)
{
_ = Message.Success("创建成功!");
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRoleInfo.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRoleInfo.razor
similarity index 82%
rename from src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRoleInfo.razor
rename to src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRoleInfo.razor
index bb2b13b..64ff7df 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRoleInfo.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRoleInfo.razor
@@ -1,7 +1,4 @@
-@using NetCorePal.D3Shop.Admin.Shared.Requests
-@using NetCorePal.D3Shop.Web.Admin.Client.Models
-@using NetCorePal.D3Shop.Web.Admin.Client.Services
-编辑
+编辑
_form = default!;
- private UpdateRoleInfoModel _roleInfoModel = new();
+ private Form _form = default!;
+ private UpdateRoleInfoRequest _roleInfoModel = new();
private void ShowModal()
{
@@ -44,7 +41,7 @@
{
_modalConfirmLoading = true;
StateHasChanged();
- var response = await RolesService.UpdateRoleInfo(Row.Id, new UpdateRoleInfoRequest(_roleInfoModel.Name, _roleInfoModel.Description));
+ var response = await RolesService.UpdateRoleInfo(Row.Id, _roleInfoModel);
_modalConfirmLoading = false;
if (response.Success)
{
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRolePermissions.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRolePermissions.razor
similarity index 59%
rename from src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRolePermissions.razor
rename to src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRolePermissions.razor
index 4b115a6..037663b 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/EditRolePermissions.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/Role/EditRolePermissions.razor
@@ -1,4 +1,4 @@
-@using NetCorePal.D3Shop.Web.Admin.Client.Services
+@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate
配置权限
- @foreach (var group in _allPermissions.GroupBy(p => p.GroupName))
+ @bind-CheckedKeys="_treeCheckedKeys">
+ @foreach (var group in _permissions.GroupBy(p => p.GroupName))
{
@foreach (var permission in group)
{
-
+
}
}
@@ -26,53 +24,38 @@
@code {
[CascadingParameter] public RoleResponse Row { get; set; } = default!;
[Inject] private IRolesService RolesService { get; set; } = default!;
- [Inject] private IPermissionsService PermissionsService { get; set; } = default!;
[Inject] private MessageService Message { get; set; } = default!;
private string[] _treeCheckedKeys = [];
- private List _allPermissions = [];
- private List _checkedPermission = [];
-
+ private List _permissions = [];
+
private bool _modalVisible;
private bool _modalConfirmLoading;
- protected override void OnInitialized()
- {
- _checkedPermission = Row.PermissionCodes.ToList();
- }
-
private async Task ShowModal()
{
_modalVisible = true;
- _allPermissions = await GetAllPermissions();
+ _permissions = await GetPermissions(Row.Id);
}
- private async Task> GetAllPermissions()
+ private async Task> GetPermissions(RoleId id)
{
- var response = await PermissionsService.GetAll();
+ var response = await RolesService.GetRolePermissions(id);
if (response.Success) return response.Data.ToList();
_ = Message.Error(response.Message);
return [];
}
- private void Tree_OnCheck(TreeEventArgs e)
- {
- _checkedPermission = _allPermissions
- .Where(p => _treeCheckedKeys.Contains(p.Code))
- .Select(p => p.Code).ToList();
- }
-
private async Task Modal_HandleOk()
{
_modalConfirmLoading = true;
StateHasChanged();
- var response = await RolesService.UpdateRolePermissions(Row.Id, _checkedPermission);
+ var response = await RolesService.UpdateRolePermissions(Row.Id, _treeCheckedKeys.ToList());
_modalConfirmLoading = false;
if (response.Success)
{
_modalVisible = false;
_ = Message.Success("更新成功!");
- Row.PermissionCodes = _checkedPermission;
}
else
{
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor
new file mode 100644
index 0000000..02048f4
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor
@@ -0,0 +1,33 @@
+@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate
+新建
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor.cs
new file mode 100644
index 0000000..766fa13
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/AddAdminUser.razor.cs
@@ -0,0 +1,71 @@
+using Microsoft.AspNetCore.Components.Forms;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+
+namespace NetCorePal.D3Shop.Web.Admin.Client.Components.User;
+
+public partial class AddAdminUser
+{
+ [Inject] private IAdminUserService AdminUserService { get; set; } = default!;
+ [Inject] private MessageService Message { get; set; } = default!;
+ [Parameter] public EventCallback OnItemAdded { get; set; }
+
+ private bool _modalVisible;
+ private bool _modalConfirmLoading;
+ private Tabs _tabs = default!;
+ private CreateAdminUserRequest _newUserModel = new();
+ private Form _form = default!;
+ private CheckboxOption[] _roleOptions = [];
+ private RoleId[] _selectedRoleIds = [];
+
+ private async Task ShowModal()
+ {
+ _modalVisible = true;
+ var allRoles = await GetAllRoleNames();
+ _roleOptions = allRoles.Select(x => new CheckboxOption
+ {
+ Label = x.RoleName,
+ Value = x.RoleId
+ }).ToArray();
+ }
+
+ private async Task> GetAllRoleNames()
+ {
+ var response = await AdminUserService.GetAllRolesForCreateUser();
+ if (response.Success) return response.Data.ToList();
+ _ = Message.Error(response.Message);
+ return [];
+ }
+
+ private void CloseModal()
+ {
+ _modalVisible = false;
+ _selectedRoleIds = [];
+ _newUserModel = new CreateAdminUserRequest();
+ _tabs.GoTo(0);
+ }
+
+ private async Task Form_OnFinish(EditContext editContext)
+ {
+ _modalConfirmLoading = true;
+ StateHasChanged();
+ _newUserModel.RoleIds = _selectedRoleIds;
+ var response = await AdminUserService.CreateAdminUser(_newUserModel);
+ if (response.Success)
+ {
+ _ = Message.Success("创建成功!");
+ CloseModal();
+ await OnItemAdded.InvokeAsync();
+ }
+ else
+ {
+ _ = Message.Error(response.Message);
+ }
+
+ _modalConfirmLoading = false;
+ }
+
+ private void Form_OnFinishFailed(EditContext editContext)
+ {
+ _tabs.GoTo(0);
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserPermissions.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserPermissions.razor
new file mode 100644
index 0000000..44268d3
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserPermissions.razor
@@ -0,0 +1,71 @@
+@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate
+配置权限
+
+
+
+ @foreach (var group in _permissions.GroupBy(p => p.GroupName))
+ {
+
+ @foreach (var permission in group)
+ {
+
+ }
+
+ }
+
+
+
+@code {
+ [CascadingParameter] public AdminUserResponse Row { get; set; } = default!;
+ [Inject] private IAdminUserService AdminUserService { get; set; } = default!;
+
+ [Inject] private MessageService Message { get; set; } = default!;
+ private string[] _treeCheckedKeys = [];
+ private AdminUserPermissionResponse[] _permissions = [];
+ private Tree _tree = default!;
+
+ private bool _modalVisible;
+ private bool _modalConfirmLoading;
+
+ private async Task ShowModal()
+ {
+ _modalVisible = true;
+ _permissions = await GetAssignedPermissions(Row.Id);
+ }
+
+ private async Task GetAssignedPermissions(AdminUserId id)
+ {
+ var response = await AdminUserService.GetAdminUserPermissions(id);
+ if (response.Success) return response.Data.ToArray();
+ _ = Message.Error(response.Message);
+ return [];
+ }
+
+ private async Task Modal_HandleOk()
+ {
+ _modalConfirmLoading = true;
+ StateHasChanged();
+ var permissions = _treeCheckedKeys.Except(
+ _permissions.Where(p => p.IsFromRole).Select(p => p.Code));
+ var response = await AdminUserService.SetAdminUserSpecificPermissions(Row.Id, permissions);
+ _modalConfirmLoading = false;
+ if (response.Success)
+ {
+ _modalVisible = false;
+ _ = Message.Success("更新成功!");
+ }
+ else
+ {
+ _ = Message.Error(response.Message);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserRoles.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserRoles.razor
new file mode 100644
index 0000000..5da9680
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Components/User/EditUserRoles.razor
@@ -0,0 +1,62 @@
+@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate
+@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate
+配置角色
+
+
+
+
+
+@code {
+ [CascadingParameter] public AdminUserResponse Row { get; set; } = default!;
+
+ [Inject] private IAdminUserService AdminUserService { get; set; } = default!;
+ [Inject] private MessageService Message { get; set; } = default!;
+
+ private CheckboxOption[] _roleOptions = [];
+ private RoleId[] _selectedRoleIds = [];
+
+ private bool _modalVisible;
+ private bool _modalConfirmLoading;
+
+ private async Task ShowModal()
+ {
+ _modalVisible = true;
+ var roles = await GetAdminUserRoles(Row.Id);
+ _roleOptions = roles.Select(x => new CheckboxOption
+ {
+ Label = x.RoleName,
+ Value = x.RoleId,
+ Checked = x.IsAssigned
+ }).ToArray();
+ }
+
+ private async Task> GetAdminUserRoles(AdminUserId id)
+ {
+ var response = await AdminUserService.GetAdminUserRoles(id);
+ if (response.Success) return response.Data.ToList();
+ _ = Message.Error(response.Message);
+ return [];
+ }
+
+ private async Task Modal_HandleOk()
+ {
+ _modalConfirmLoading = true;
+ StateHasChanged();
+ var response = await AdminUserService.UpdateAdminUserRoles(Row.Id, _selectedRoleIds);
+ _modalConfirmLoading = false;
+ if (response.Success)
+ {
+ _modalVisible = false;
+ _ = Message.Success("更新成功!");
+ }
+ else
+ {
+ _ = Message.Error(response.Message);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/PermissionExtensions.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/PermissionExtensions.cs
index 1f24f03..c370c33 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/PermissionExtensions.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/PermissionExtensions.cs
@@ -1,6 +1,7 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using NetCorePal.D3Shop.Admin.Shared.Const;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
namespace NetCorePal.D3Shop.Web.Admin.Client.Extensions;
@@ -8,8 +9,9 @@ internal static class PermissionExtensions
{
internal static bool CheckPermission(this AuthenticationState authenticationState, string permission)
{
- return authenticationState.User.Claims
- .Any(claim => claim is { Type: ClaimTypes.Role, Value: AppClaim.SuperAdminRole })
- || authenticationState.User.HasClaim(AppClaim.AdminPermission, permission);
+ // 系统默认用户不校验权限
+ var name = authenticationState.User.Claims.Single(c => c.Type == ClaimTypes.Name).Value;
+ return name == AppDefaultCredentials.Name ||
+ authenticationState.User.HasClaim(AppClaim.AdminPermission, permission);
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/RefitServiceCollectionExtensions.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/RefitServiceCollectionExtensions.cs
new file mode 100644
index 0000000..cfd9442
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Extensions/RefitServiceCollectionExtensions.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using NetCorePal.D3Shop.Web.Admin.Client.Attributes;
+
+namespace NetCorePal.D3Shop.Web.Admin.Client.Extensions;
+
+public static class RefitServiceCollectionExtensions
+{
+ ///
+ /// 批量注册标记了 特性的 Refit 服务接口。
+ ///
+ ///
+ ///
+ public static void AddRefitServices(this IServiceCollection services, string baseUrl)
+ {
+ // 获取所有标记了 RefitServiceAttribute 特性的接口
+ var serviceTypes = Assembly.GetExecutingAssembly().GetTypes()
+ .Where(t => t.IsInterface && t.GetCustomAttribute() != null);
+
+ var ser = new NewtonsoftJsonContentSerializer();
+ var settings = new RefitSettings(ser);
+ foreach (var serviceType in serviceTypes)
+ {
+ services.AddRefitClient(serviceType, settings)
+ .ConfigureHttpClient(c => c.BaseAddress = new Uri(baseUrl));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/GlobalUsings.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/GlobalUsings.cs
index 1a10314..7e90a7f 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/GlobalUsings.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/GlobalUsings.cs
@@ -1,4 +1,7 @@
global using AntDesign;
+global using Microsoft.AspNetCore.Components;
+global using NetCorePal.D3Shop.Admin.Shared.Requests;
global using NetCorePal.D3Shop.Admin.Shared.Responses;
+global using NetCorePal.D3Shop.Web.Admin.Client.Services;
global using NetCorePal.Extensions.Dto;
-global using Refit;
\ No newline at end of file
+global using Refit;
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Models/CreateRoleModel.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Models/CreateRoleModel.cs
deleted file mode 100644
index 961251e..0000000
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Models/CreateRoleModel.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace NetCorePal.D3Shop.Web.Admin.Client.Models;
-
-public class CreateRoleModel
-{
- [Required] public string Name { get; set; } = string.Empty;
- [Required] public string Description { get; set; } = string.Empty;
- public List PermissionCodes { get; set; } = [];
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Models/UpdateRoleInfoModel.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Models/UpdateRoleInfoModel.cs
deleted file mode 100644
index b22bc8a..0000000
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Models/UpdateRoleInfoModel.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace NetCorePal.D3Shop.Web.Admin.Client.Models;
-
-public class UpdateRoleInfoModel
-{
- [Required] public string Name { get; set; } = string.Empty;
- [Required] public string Description { get; set; } = string.Empty;
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/NetCorePal.D3Shop.Web.Admin.Client.csproj b/src/NetCorePal.D3Shop.Web.Admin.Client/NetCorePal.D3Shop.Web.Admin.Client.csproj
index de82818..7603e0c 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/NetCorePal.D3Shop.Web.Admin.Client.csproj
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/NetCorePal.D3Shop.Web.Admin.Client.csproj
@@ -16,19 +16,13 @@
-
-
-
-
-
- <_ContentIncludedByDefault Remove="Pages\Account\Pages\Login.razor" />
- <_ContentIncludedByDefault Remove="Account\Pages\Login.razor" />
+
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.Razor.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.Razor.cs
index 50e0dcc..82ec4db 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.Razor.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.Razor.cs
@@ -1,6 +1,4 @@
-using Microsoft.AspNetCore.Components;
-using NetCorePal.D3Shop.Admin.Shared.Requests;
-using NetCorePal.D3Shop.Web.Admin.Client.Services;
+using AntDesign.TableModels;
namespace NetCorePal.D3Shop.Web.Admin.Client.Pages;
@@ -13,7 +11,7 @@ public sealed partial class Roles : IDisposable
private PersistingComponentStateSubscription _persistingSubscription;
- private List _roleList = [];
+ private PagedData _pagedRoles = default!;
private ITable _table = default!;
@@ -22,27 +20,34 @@ protected override async Task OnInitializedAsync()
const string persistKey = "roles";
_persistingSubscription = ApplicationState.RegisterOnPersisting(() =>
{
- ApplicationState.PersistAsJson(persistKey, _roleList);
+ ApplicationState.PersistAsJson(persistKey, _pagedRoles);
return Task.CompletedTask;
});
- if (ApplicationState.TryTakeFromJson>(persistKey, out var restored))
- _roleList = restored!;
+ if (ApplicationState.TryTakeFromJson>(persistKey, out var restored))
+ _pagedRoles = restored!;
else
- _roleList = await GetAllRoles();
+ await GetPagedRoles();
}
- private async Task> GetAllRoles()
+ private readonly RoleQueryRequest _roleQueryRequest =
+ new() { PageIndex = 1, PageSize = 10, CountTotal = true };
+
+ private async Task GetPagedRoles()
{
- var response = await RolesService.GetAllRoles();
- if (response.Success) return response.Data.ToList();
- _ = Message.Error(response.Message);
- return [];
+ var response = await RolesService.GetAllRoles(_roleQueryRequest);
+ if (response.Success)
+ {
+ _pagedRoles = response.Data;
+ _roleQueryRequest.PageIndex = _pagedRoles.PageIndex;
+ _roleQueryRequest.PageSize = _pagedRoles.PageSize;
+ }
+ else _ = Message.Error(response.Message);
}
private async Task HandleItemAdded()
{
- _roleList = await GetAllRoles();
+ await GetPagedRoles();
}
private void HandleItemUpdated()
@@ -58,7 +63,7 @@ private async Task Delete(RoleResponse row)
if (response.Success)
{
_ = Message.Success("删除成功!");
- _roleList = await GetAllRoles();
+ await GetPagedRoles();
}
else
{
@@ -71,13 +76,14 @@ private async Task Confirm(string message)
return await ConfirmService.Show(message, "警告", ConfirmButtons.YesNo, ConfirmIcon.Warning) == ConfirmResult.Yes;
}
- private string _searchString = default!;
-
private async Task OnSearch()
{
- var response = await RolesService.GetRolesByCondition(new RoleQueryRequest(_searchString, null));
- if (response.Success) _roleList = response.Data.ToList();
- else _ = Message.Error(response.Message);
+ await GetPagedRoles();
+ }
+
+ private async Task Table_OnChange(QueryModel obj)
+ {
+ await GetPagedRoles();
}
public void Dispose()
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.razor
index 643c340..c40c0e6 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Roles.razor
@@ -1,19 +1,32 @@
@page "/admin/roles"
-@using NetCorePal.D3Shop.Web.Admin.Client.Components
+@using NetCorePal.D3Shop.Web.Admin.Client.Components.Role
@using NetCorePal.D3Shop.Web.Admin.Client.Extensions
+
@attribute [ClientPermission(PermissionDefinitions.RoleView)]
+ DataSource="_pagedRoles.Items"
+ Total="_pagedRoles.Total"
+ @bind-PageIndex="_roleQueryRequest.PageIndex"
+ @bind-PageSize="_roleQueryRequest.PageSize"
+ OnChange="Table_OnChange">
+
+
+
角色列表
-
+
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/TestComponent.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/TestComponent.razor
index f534e48..4cfba98 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/TestComponent.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/TestComponent.razor
@@ -1,73 +1,2 @@
@page "/test/component"
-此页面用于测试组件样式和行为
-
-
- @foreach (var group in GroupedPermissions)
- {
-
- @foreach (var permission in group.Value)
- {
-
- }
-
- }
-
-
-Selected Permissions:
-
- @foreach (var selected in SelectedPermissions)
- {
- @selected.Remark (@selected.Code) - Group: @selected.GroupName
- }
-
-
-@code {
-
- // 假设的权限数据
- private List Permissions = new()
- {
- new Permission("Code1", "Group1", "Remark1"),
- new Permission("Code2", "Group1", "Remark2"),
- new Permission("Code3", "Group2", "Remark3"),
- new Permission("Code4", "Group3", "Remark4"),
- };
-
- // 按 GroupName 分组的权限
- private Dictionary> GroupedPermissions = [];
-
- // 树组件引用
- private Tree tree = default!;
-
- // 选中的节点 Key
- private string[] CheckedKeys = [];
-
- // 选中的权限
- private List SelectedPermissions = new();
-
- protected override void OnInitialized()
- {
- // 按 GroupName 分组
- GroupedPermissions = Permissions
- .GroupBy(p => p.GroupName)
- .ToDictionary(g => g.Key, g => g.ToList());
- }
-
- private void HandleCheck(TreeEventArgs e)
- {
- // 获取选中的权限
- SelectedPermissions = Permissions
- .Where(p => CheckedKeys.Contains(p.Code))
- .ToList();
- }
-
- // 权限数据模型
- public record Permission(string Code, string GroupName, string Remark);
-
-}
\ No newline at end of file
+此页面用于测试组件样式和行为
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor
index d17ea60..eccaf72 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor
@@ -1,6 +1,68 @@
@page "/admin/users"
-用户列表
+@using NetCorePal.D3Shop.Web.Admin.Client.Extensions
+@using NetCorePal.D3Shop.Web.Admin.Client.Components.User
-@code {
-
-}
+@attribute [ClientPermission(PermissionDefinitions.AdminUserView)]
+
+
+
+
+
+
+
+
+ 用户列表
+
+
+
+
+
+
+ @if (context.CheckPermission(PermissionDefinitions.AdminUserCreate))
+ {
+
+ }
+
+
+
+
+
+
+
+
+
+ @if (context.CheckPermission(PermissionDefinitions.AdminUserUpdateRoles))
+ {
+
+
+
+ }
+
+
+ @if (context.CheckPermission(PermissionDefinitions.AdminUserSetPermissions))
+ {
+
+
+
+ }
+
+
+ @if (context.CheckPermission(PermissionDefinitions.AdminUserDelete))
+ {
+ Delete(row)">删除
+ }
+
+
+
+
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor.cs
new file mode 100644
index 0000000..6030e01
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Pages/Users.razor.cs
@@ -0,0 +1,88 @@
+using AntDesign.TableModels;
+
+namespace NetCorePal.D3Shop.Web.Admin.Client.Pages;
+
+public sealed partial class Users : IDisposable
+{
+ [Inject] private IAdminUserService AdminUserService { get; set; } = default!;
+ [Inject] private MessageService Message { get; set; } = default!;
+ [Inject] private ConfirmService ConfirmService { get; set; } = default!;
+ [Inject] private PersistentComponentState ApplicationState { get; set; } = default!;
+
+ private PersistingComponentStateSubscription _persistingSubscription;
+
+ private PagedData _pagedAdminUsers = default!;
+
+ protected override async Task OnInitializedAsync()
+ {
+ const string persistKey = "adminUsers";
+ _persistingSubscription = ApplicationState.RegisterOnPersisting(() =>
+ {
+ ApplicationState.PersistAsJson(persistKey, _pagedAdminUsers);
+ return Task.CompletedTask;
+ });
+
+ if (ApplicationState.TryTakeFromJson>(persistKey, out var restored))
+ _pagedAdminUsers = restored!;
+ else
+ await GetPagedAdminUsers();
+ }
+
+ private readonly AdminUserQueryRequest _adminUserQueryRequest =
+ new() { PageIndex = 1, PageSize = 10, CountTotal = true };
+
+ private async Task GetPagedAdminUsers()
+ {
+ var response = await AdminUserService.GetAllAdminUsers(_adminUserQueryRequest);
+ if (response.Success)
+ {
+ _pagedAdminUsers = response.Data;
+ _adminUserQueryRequest.PageIndex = _pagedAdminUsers.PageIndex;
+ _adminUserQueryRequest.PageSize = _pagedAdminUsers.PageSize;
+ }
+ else _ = Message.Error(response.Message);
+ }
+
+ private async Task HandleItemAdded()
+ {
+ await GetPagedAdminUsers();
+ }
+
+ private async Task Delete(AdminUserResponse row)
+ {
+ if (!await Confirm($"确认删除用户:{row.Name}?"))
+ return;
+ var response = await AdminUserService.DeleteAdminUser(row.Id);
+ if (response.Success)
+ {
+ _ = Message.Success("删除成功!");
+ await GetPagedAdminUsers();
+ }
+ else
+ {
+ _ = Message.Error(response.Message);
+ }
+ }
+
+ private async Task Confirm(string message)
+ {
+ return await ConfirmService.Show(message, "警告", ConfirmButtons.YesNo, ConfirmIcon.Warning) == ConfirmResult.Yes;
+ }
+
+ private string _searchString = default!;
+
+ private async Task OnSearch()
+ {
+ await GetPagedAdminUsers();
+ }
+
+ private async Task Table_OnChange(QueryModel obj)
+ {
+ await GetPagedAdminUsers();
+ }
+
+ public void Dispose()
+ {
+ _persistingSubscription.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Program.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Program.cs
index 781a223..758c95c 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Program.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Program.cs
@@ -4,8 +4,7 @@
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using NetCorePal.D3Shop.Admin.Shared.Authorization;
using NetCorePal.D3Shop.Web.Admin.Client.Auth;
-using NetCorePal.D3Shop.Web.Admin.Client.Services;
-using Newtonsoft.Json;
+using NetCorePal.D3Shop.Web.Admin.Client.Extensions;
namespace NetCorePal.D3Shop.Web.Admin.Client
{
@@ -15,22 +14,15 @@ public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
- builder.Services.AddRefitClient()
- .ConfigureHttpClient(c => c.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
-
- var ser = new NewtonsoftJsonContentSerializer(new JsonSerializerSettings { });
- var settings = new RefitSettings(ser);
- builder.Services.AddRefitClient(settings)
- .ConfigureHttpClient(c => c.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
- builder.Services.AddRefitClient(settings)
- .ConfigureHttpClient(c => c.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
+ // Services注册
+ builder.Services.AddRefitServices(builder.HostEnvironment.BaseAddress);
#region 身份认证和授权
builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddSingleton();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/ServiceExceptionHandler.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/ServiceExceptionHandler.cs
new file mode 100644
index 0000000..4b3ce0e
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/ServiceExceptionHandler.cs
@@ -0,0 +1,22 @@
+namespace NetCorePal.D3Shop.Web.Admin.Client;
+
+public class ServiceExceptionHandler(MessageService messageService) : DelegatingHandler
+{
+ protected override async Task SendAsync(
+ HttpRequestMessage request,
+ CancellationToken cancellationToken)
+ {
+ try
+ {
+ var result = await base.SendAsync(request, cancellationToken);
+ result.EnsureSuccessStatusCode();
+
+ return result;
+ }
+ catch (Exception)
+ {
+ _ = messageService.Error("服务内部异常!");
+ throw;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IAdminUserService.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IAdminUserService.cs
new file mode 100644
index 0000000..c372087
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IAdminUserService.cs
@@ -0,0 +1,33 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Web.Admin.Client.Attributes;
+
+namespace NetCorePal.D3Shop.Web.Admin.Client.Services;
+
+[RefitService]
+public interface IAdminUserService
+{
+ [Post("/api/AdminUser/CreateAdminUser")]
+ Task> CreateAdminUser([Body] CreateAdminUserRequest request);
+
+ [Get("/api/AdminUser/GetAllAdminUsers")]
+ Task>> GetAllAdminUsers([Query] AdminUserQueryRequest request);
+
+ [Get("/api/AdminUser/GetAdminUserRoles/{id}")]
+ Task>> GetAdminUserRoles(AdminUserId id);
+
+ [Put("/api/AdminUser/UpdateAdminUserRoles/{id}")]
+ Task UpdateAdminUserRoles(AdminUserId id, [Body] IEnumerable roleIds);
+
+ [Delete("/api/AdminUser/DeleteAdminUser/{id}")]
+ Task DeleteAdminUser(AdminUserId id);
+
+ [Get("/api/AdminUser/GetAllRolesForCreateUser")]
+ Task>> GetAllRolesForCreateUser();
+
+ [Get("/api/AdminUser/GetAdminUserPermissions/{id}")]
+ Task>> GetAdminUserPermissions(AdminUserId id);
+
+ [Put("/api/AdminUser/SetAdminUserSpecificPermissions/{id}")]
+ Task SetAdminUserSpecificPermissions(AdminUserId id, [Body] IEnumerable permissionCodes);
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IPermissionsService.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IPermissionsService.cs
deleted file mode 100644
index d502331..0000000
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/Services/IPermissionsService.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission;
-
-namespace NetCorePal.D3Shop.Web.Admin.Client.Services;
-
-public interface IPermissionsService
-{
- [Get("/api/Permission/GetAll")]
- Task>> GetAll();
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/UserInfo.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/UserInfo.cs
index 61ac7e9..e452de6 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/UserInfo.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/UserInfo.cs
@@ -5,8 +5,7 @@ namespace NetCorePal.D3Shop.Web.Admin.Client
public class UserInfo
{
public required string UserId { get; init; }
- public required IEnumerable Roles { get; init; }
-
+ public required string Name { get; init; }
public required IEnumerable Permissions { get; init; }
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/_Imports.razor b/src/NetCorePal.D3Shop.Web.Admin.Client/_Imports.razor
index a52fa38..cb958d4 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/_Imports.razor
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/_Imports.razor
@@ -5,18 +5,21 @@
@using AntDesign.Charts
@using AntDesign.Extensions.Localization
@using AntDesign.ProLayout
+@using Microsoft.AspNetCore.Components;
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
-@using NetCorePal.D3Shop.Web.Admin.Client.Auth
@using NetCorePal.D3Shop.Admin.Shared.Const
+@using NetCorePal.D3Shop.Admin.Shared.Requests
@using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission
@using NetCorePal.D3Shop.Web.Admin
+@using NetCorePal.D3Shop.Web.Admin.Client.Auth
@using NetCorePal.D3Shop.Web.Admin.Client.Layouts
@using NetCorePal.D3Shop.Web.Admin.Client.Pages.Exception._403
@using NetCorePal.D3Shop.Web.Admin.Client.Pages.Exception._404
@using NetCorePal.D3Shop.Web.Admin.Client.Pages.Exception._500
+@using NetCorePal.D3Shop.Web.Admin.Client.Services;
@using static Microsoft.AspNetCore.Components.Web.RenderMode
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/services/IAccountService.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/services/IAccountService.cs
index ef38eaf..6be503e 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/services/IAccountService.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/services/IAccountService.cs
@@ -1,9 +1,8 @@
-using NetCorePal.D3Shop.Admin.Shared.Requests;
-using NetCorePal.D3Shop.Admin.Shared.Responses;
-
+using NetCorePal.D3Shop.Web.Admin.Client.Attributes;
namespace NetCorePal.D3Shop.Web.Admin.Client.Services;
+[RefitService]
public interface IAccountService
{
[Post("/api/AdminUserAccount/login")]
diff --git a/src/NetCorePal.D3Shop.Web.Admin.Client/services/IRolesService.cs b/src/NetCorePal.D3Shop.Web.Admin.Client/services/IRolesService.cs
index 389456d..e3cd518 100644
--- a/src/NetCorePal.D3Shop.Web.Admin.Client/services/IRolesService.cs
+++ b/src/NetCorePal.D3Shop.Web.Admin.Client/services/IRolesService.cs
@@ -1,15 +1,16 @@
-using NetCorePal.D3Shop.Admin.Shared.Requests;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Web.Admin.Client.Attributes;
namespace NetCorePal.D3Shop.Web.Admin.Client.Services;
+[RefitService]
public interface IRolesService
{
[Post("/api/Role/CreateRole")]
Task> CreateRole([Body] CreateRoleRequest request);
[Get("/api/Role/GetAllRoles")]
- Task>> GetAllRoles();
+ Task>> GetAllRoles([Query] RoleQueryRequest request);
[Put("/api/Role/UpdateRoleInfo/{id}")]
Task UpdateRoleInfo(RoleId id, [Body] UpdateRoleInfoRequest request);
@@ -20,12 +21,9 @@ public interface IRolesService
[Delete("/api/Role/DeleteRole/{id}")]
Task DeleteRole(RoleId id);
- [Get("/api/Role/GetRolesByCondition")]
- Task>> GetRolesByCondition([Query] RoleQueryRequest request);
-
- [Get("/api/Role/GetRoleById/{id}")]
- Task> GetRoleById(RoleId id);
-
[Get("/api/Role/GetRolePermissions/{id}")]
- Task>> GetRolePermissions(RoleId id);
+ Task>> GetRolePermissions(RoleId id);
+
+ [Get("/api/Role/GetAllPermissionsForCreateRole")]
+ Task>> GetAllPermissionsForCreateRole();
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateAdminUserCommand.cs b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateAdminUserCommand.cs
index 4167aea..64113ea 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateAdminUserCommand.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateAdminUserCommand.cs
@@ -7,7 +7,11 @@
namespace NetCorePal.D3Shop.Web.Application.Commands.Identity;
-public record CreateAdminUserCommand(string Name, string Phone, string Password, IEnumerable RolesToBeAssigned)
+public record CreateAdminUserCommand(
+ string Name,
+ string Phone,
+ string Password,
+ IEnumerable RolesToBeAssigned)
: ICommand;
public class CreateAdminUserCommandValidator : AbstractValidator
@@ -17,8 +21,7 @@ public CreateAdminUserCommandValidator(AdminUserQuery adminUserQuery)
RuleFor(u => u.Name).NotEmpty().WithMessage("用户名不能为空");
RuleFor(u => u.Phone).NotEmpty().WithMessage("手机号不能为空");
RuleFor(u => u.Password).NotEmpty().WithMessage("密码不能为空");
- RuleFor(u => u.Name).Must(n =>
- adminUserQuery.GetAdminUserByNameAsync(n, CancellationToken.None).GetAwaiter().GetResult() is null)
+ RuleFor(u => u.Name).MustAsync(async (n, ct) => !await adminUserQuery.DoesAdminUserExist(n, ct))
.WithMessage(u => $"该用户已存在,Name={u.Name}");
}
}
diff --git a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateRoleCommand.cs b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateRoleCommand.cs
index 6a957f5..78395ca 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateRoleCommand.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/CreateRoleCommand.cs
@@ -6,14 +6,15 @@
namespace NetCorePal.D3Shop.Web.Application.Commands.Identity;
-public record CreateRoleCommand(string Name, string Description, IEnumerable Permissions) : ICommand;
+public record CreateRoleCommand(string Name, string Description, IEnumerable Permissions)
+ : ICommand;
public class CreateRoleCommandValidator : AbstractValidator
{
public CreateRoleCommandValidator(RoleQuery roleQuery)
{
RuleFor(x => x.Name).NotEmpty().WithMessage("角色名称不能为空");
- RuleFor(x => x.Name).Must((n) => roleQuery.GetRoleByNameAsync(n, CancellationToken.None).GetAwaiter().GetResult() is null)
+ RuleFor(x => x.Name).MustAsync(async (n, ct) => !await roleQuery.RoleExistsByNameAsync(n, ct))
.WithMessage(r => $"角色名称重复,Name={r.Name}");
}
}
diff --git a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/DeleteRoleCommand.cs b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/DeleteRoleCommand.cs
index 8d2ed70..92265fe 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/DeleteRoleCommand.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/DeleteRoleCommand.cs
@@ -13,11 +13,9 @@ public class DeleteRoleCommandValidator : AbstractValidator
public DeleteRoleCommandValidator(AdminUserQuery adminUserQuery)
{
RuleFor(x => x.RoleId).NotEmpty();
- RuleFor(x => new { x.RoleId }).Must((r) =>
- {
- var s = adminUserQuery.GetAdminUserByRoleIdAsync(r.RoleId, CancellationToken.None).GetAwaiter().GetResult();
- return s.Count == 0;
- }).WithMessage("该角色已分配用户,无法删除");
+ RuleFor(x => x.RoleId).MustAsync(async (rId, ct) =>
+ !await adminUserQuery.DoesAdminUserExist(rId, ct)
+ ).WithMessage("该角色已分配用户,无法删除");
}
}
@@ -26,7 +24,7 @@ public class DeleteRoleCommandHandler(IRoleRepository roleRepository) : ICommand
public async Task Handle(DeleteRoleCommand request, CancellationToken cancellationToken)
{
var role = await roleRepository.GetAsync(request.RoleId, cancellationToken) ??
- throw new KnownException($"未找到角色,RoleId = {request.RoleId}");
+ throw new KnownException($"未找到角色,RoleId = {request.RoleId}");
await roleRepository.RemoveAsync(role);
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/SetAdminUserSpecificPermissions.cs b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/SetAdminUserSpecificPermissions.cs
new file mode 100644
index 0000000..c43002a
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/SetAdminUserSpecificPermissions.cs
@@ -0,0 +1,19 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+using NetCorePal.D3Shop.Infrastructure.Repositories.Identity;
+using NetCorePal.Extensions.Primitives;
+
+namespace NetCorePal.D3Shop.Web.Application.Commands.Identity;
+
+public record SetAdminUserSpecificPermissions(AdminUserId Id, IEnumerable Permissions) : ICommand;
+
+public class SetAdminUserSpecificPermissionsCommandHandler(IAdminUserRepository adminUserRepository)
+ : ICommandHandler
+{
+ public async Task Handle(SetAdminUserSpecificPermissions request, CancellationToken cancellationToken)
+ {
+ var adminUser = await adminUserRepository.GetAsync(request.Id, cancellationToken) ??
+ throw new KnownException($"用户不存在,AdminUserId={request.Id}");
+
+ adminUser.SetSpecificPermissions(request.Permissions);
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/UpdateRoleInfoCommand.cs b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/UpdateRoleInfoCommand.cs
index b5e7026..f77657e 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/UpdateRoleInfoCommand.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Commands/Identity/UpdateRoleInfoCommand.cs
@@ -15,10 +15,8 @@ public UpdateRoleInfoCommandValidator(RoleQuery roleQuery)
RuleFor(x => x.RoleId).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => new { x.Name, x.RoleId }).MustAsync(async (r, ct) =>
- {
- var s = await roleQuery.GetRoleByNameAsync(r.Name, ct);
- return s is null || s.Id == r.RoleId;
- });
+ !await roleQuery.RoleExistsByNameAsync(r.Name, r.RoleId, ct)
+ );
}
}
@@ -27,7 +25,7 @@ public class UpdateRoleInfoCommandHandler(IRoleRepository roleRepository) : ICom
public async Task Handle(UpdateRoleInfoCommand request, CancellationToken cancellationToken)
{
var role = await roleRepository.GetAsync(request.RoleId, cancellationToken) ??
- throw new KnownException($"未找到角色,RoleId = {request.RoleId}");
+ throw new KnownException($"未找到角色,RoleId = {request.RoleId}");
role.UpdateRoleInfo(request.Name, request.Description);
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RoleInfoChangedDomainEventHandler.cs b/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RoleInfoChangedDomainEventHandler.cs
index 0e4b27b..926bad2 100644
--- a/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RoleInfoChangedDomainEventHandler.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RoleInfoChangedDomainEventHandler.cs
@@ -1,5 +1,4 @@
using MediatR;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using NetCorePal.D3Shop.Domain.DomainEvents.Identity;
using NetCorePal.D3Shop.Web.Application.Commands.Identity;
using NetCorePal.D3Shop.Web.Application.Queries.Identity;
@@ -7,15 +6,16 @@
namespace NetCorePal.D3Shop.Web.Application.DomainEventHandlers.Identity;
-public class RoleInfoChangedDomainEventHandler(IMediator mediator, AdminUserQuery adminUserQuery) : IDomainEventHandler
+public class RoleInfoChangedDomainEventHandler(IMediator mediator, AdminUserQuery adminUserQuery)
+ : IDomainEventHandler
{
public async Task Handle(RoleInfoChangedDomainEvent notification, CancellationToken cancellationToken)
{
var role = notification.Role;
- var adminUsers = await adminUserQuery.GetAdminUserByRoleIdAsync(role.Id, cancellationToken);
- foreach (var adminUser in adminUsers)
+ var adminUserIds = await adminUserQuery.GetAdminUserIdsByRoleIdAsync(role.Id, cancellationToken);
+ foreach (var adminUserId in adminUserIds)
{
- await mediator.Send(new UpdateAdminUserRoleInfoCommand(adminUser.Id, role.Id, role.Name),
+ await mediator.Send(new UpdateAdminUserRoleInfoCommand(adminUserId, role.Id, role.Name),
cancellationToken);
}
}
diff --git a/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RolePermissionsChangedDomainEventHandler.cs b/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RolePermissionsChangedDomainEventHandler.cs
index 43d7715..57aedef 100644
--- a/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RolePermissionsChangedDomainEventHandler.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/DomainEventHandlers/Identity/RolePermissionsChangedDomainEventHandler.cs
@@ -17,17 +17,16 @@ public class RolePermissionsChangedDomainEventHandler(
public async Task Handle(RolePermissionChangedDomainEvent notification, CancellationToken cancellationToken)
{
var roleId = notification.Role.Id;
- var adminUsers = await adminUserQuery.GetAdminUserByRoleIdAsync(roleId, cancellationToken);
+ var adminUserIds = await adminUserQuery.GetAdminUserIdsByRoleIdAsync(roleId, cancellationToken);
var permissions = notification.Role.Permissions
.Select(p => new AdminUserPermission(p.PermissionCode, p.PermissionRemark))
.ToArray();
- await Task.WhenAll(
- adminUsers.Select(async adminUser =>
- {
- memoryCache.Remove($"{CacheKeys.AdminUserPermissions}:{adminUser.Id}");
- await mediator.Send(new UpdateAdminUserRolePermissionsCommand(adminUser.Id, roleId, permissions),
- cancellationToken);
- })
- );
+
+ foreach (var adminUserId in adminUserIds)
+ {
+ memoryCache.Remove($"{CacheKeys.AdminUserPermissions}:{adminUserId}");
+ await mediator.Send(new UpdateAdminUserRolePermissionsCommand(adminUserId, roleId, permissions),
+ cancellationToken);
+ }
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Mappers/AdminUserToAdminUserResponse.cs b/src/NetCorePal.D3Shop.Web/Application/Mappers/AdminUserToAdminUserResponse.cs
deleted file mode 100644
index 3ef70b6..0000000
--- a/src/NetCorePal.D3Shop.Web/Application/Mappers/AdminUserToAdminUserResponse.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using NetCorePal.D3Shop.Admin.Shared.Responses;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
-using NetCorePal.Extensions.Mappers;
-
-namespace NetCorePal.D3Shop.Web.Application.Mappers;
-
-public class AdminUserToAdminUserResponse : IMapper
-{
- public AdminUserResponse To(AdminUser from)
- {
- return new AdminUserResponse(from.Id, from.Name, from.Phone, from.Roles, from.Permissions);
- }
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Mappers/RoleToRoleResponse.cs b/src/NetCorePal.D3Shop.Web/Application/Mappers/RoleToRoleResponse.cs
deleted file mode 100644
index 7faba4d..0000000
--- a/src/NetCorePal.D3Shop.Web/Application/Mappers/RoleToRoleResponse.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using NetCorePal.D3Shop.Admin.Shared.Responses;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
-using NetCorePal.Extensions.Mappers;
-
-namespace NetCorePal.D3Shop.Web.Application.Mappers;
-
-public class RoleToRoleResponse : IMapper
-{
- public RoleResponse To(Role from)
- {
- return new RoleResponse(from.Id, from.Name, from.Description, from.Permissions.Select(p => p.PermissionCode));
- }
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/AdminUserQuery.cs b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/AdminUserQuery.cs
index b0ade68..69d1b1f 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/AdminUserQuery.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/AdminUserQuery.cs
@@ -1,50 +1,85 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
+using NetCorePal.D3Shop.Admin.Shared.Requests;
+using NetCorePal.D3Shop.Admin.Shared.Responses;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Web.Application.Queries.Identity.QueryResult;
using NetCorePal.D3Shop.Web.Const;
+using NetCorePal.D3Shop.Web.Extensions;
+using NetCorePal.Extensions.Dto;
+using NetCorePal.Extensions.Primitives;
namespace NetCorePal.D3Shop.Web.Application.Queries.Identity;
-public class AdminUserQuery(ApplicationDbContext applicationDbContext, IMemoryCache memoryCache)
+public class AdminUserQuery(ApplicationDbContext applicationDbContext, IMemoryCache memoryCache) : IQuery
{
- public async Task GetAdminUserByIdAsync(AdminUserId id, CancellationToken cancellationToken)
+ private DbSet AdminUserSet { get; } = applicationDbContext.AdminUsers;
+
+ public async Task GetUserCredentialsIfExists(AdminUserId id,
+ CancellationToken cancellationToken)
{
- return await applicationDbContext.AdminUsers.FindAsync([id], cancellationToken);
+ return await AdminUserSet
+ .Where(au => au.Id == id)
+ .Select(au => new AdminUserCredentials(au.Id, au.Password))
+ .FirstOrDefaultAsync(cancellationToken);
}
- public async Task> GetAdminUsersByCondition(string? name, string? phone)
+ public async Task> GetAssignedRoleIdsAsync(AdminUserId id, CancellationToken cancellationToken)
{
- var queryable = applicationDbContext.AdminUsers.AsQueryable();
-
- if (!string.IsNullOrWhiteSpace(name))
- queryable = queryable.Where(x => x.Name.Contains(name));
- if (!string.IsNullOrWhiteSpace(phone))
- queryable = queryable.Where(x => x.Phone.Contains(phone));
-
- return await queryable.ToListAsync();
+ return await AdminUserSet
+ .Where(u => u.Id == id)
+ .SelectMany(u => u.Roles.Select(ur => ur.RoleId))
+ .ToListAsync(cancellationToken);
}
- public async Task GetAdminUserByNameAsync(string name, CancellationToken cancellationToken)
+ public async Task> GetAssignedPermissionsAsync(AdminUserId id,
+ CancellationToken cancellationToken)
{
- var adminUser =
- await applicationDbContext.AdminUsers.FirstOrDefaultAsync(u => u.Name == name, cancellationToken);
+ return await AdminUserSet
+ .Where(au => au.Id == id)
+ .SelectMany(au => au.Permissions)
+ .ToListAsync(cancellationToken);
+ }
- return adminUser;
+ public async Task GetUserInfoForLoginAsync(string name,
+ CancellationToken cancellationToken)
+ {
+ return await AdminUserSet
+ .Where(au => au.Name == name)
+ .Select(au => new AuthenticationUserInfo(au.Id, au.Name, au.Password, au.Phone))
+ .FirstOrDefaultAsync(cancellationToken: cancellationToken);
}
- public async Task> GetAllAdminUsersAsync(CancellationToken cancellationToken)
+ public async Task> GetAllAdminUsersAsync(AdminUserQueryRequest queryRequest,
+ CancellationToken cancellationToken)
{
- var adminUsers = await applicationDbContext.AdminUsers.ToListAsync(cancellationToken);
+ var adminUsers = await AdminUserSet
+ .WhereIf(!queryRequest.Name.IsNullOrWhiteSpace(), au => au.Name.Contains(queryRequest.Name!))
+ .WhereIf(!queryRequest.Phone.IsNullOrWhiteSpace(), au => au.Phone.Contains(queryRequest.Phone!))
+ .Select(au => new AdminUserResponse(au.Id, au.Name, au.Phone))
+ .ToPagedDataAsync(queryRequest, cancellationToken);
return adminUsers;
}
- public async Task> GetAdminUserByRoleIdAsync(RoleId roleId, CancellationToken cancellationToken)
+ public async Task> GetAdminUserIdsByRoleIdAsync(RoleId roleId,
+ CancellationToken cancellationToken)
{
- var adminUsers = await applicationDbContext.AdminUsers
+ return await applicationDbContext.AdminUsers
.Where(x => x.Roles.Any(r => r.RoleId == roleId))
+ .Select(x => x.Id)
.ToListAsync(cancellationToken);
- return adminUsers;
+ }
+
+ public async Task DoesAdminUserExist(string userName, CancellationToken cancellationToken)
+ {
+ return await AdminUserSet.AnyAsync(au => au.Name == userName, cancellationToken);
+ }
+
+ public async Task DoesAdminUserExist(RoleId roleId, CancellationToken cancellationToken)
+ {
+ return await AdminUserSet
+ .AnyAsync(x => x.Roles.Any(r => r.RoleId == roleId), cancellationToken: cancellationToken);
}
public async Task?> GetAdminUserPermissionCodes(AdminUserId id)
@@ -58,7 +93,7 @@ public async Task> GetAdminUserByRoleIdAsync(RoleId roleId, Canc
.SelectMany(au => au.Permissions.Select(p => p.PermissionCode))
.ToListAsync();
});
-
+
return adminUserPermissions;
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AdminUserCredentials.cs b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AdminUserCredentials.cs
new file mode 100644
index 0000000..6e19846
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AdminUserCredentials.cs
@@ -0,0 +1,5 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+
+namespace NetCorePal.D3Shop.Web.Application.Queries.Identity.QueryResult;
+
+public record AdminUserCredentials(AdminUserId Id, string Password);
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AuthenticationUserInfo.cs b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AuthenticationUserInfo.cs
new file mode 100644
index 0000000..3918ef6
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/QueryResult/AuthenticationUserInfo.cs
@@ -0,0 +1,5 @@
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+
+namespace NetCorePal.D3Shop.Web.Application.Queries.Identity.QueryResult;
+
+public record AuthenticationUserInfo(AdminUserId Id,string Name,string Password,string Phone);
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/RoleQuery.cs b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/RoleQuery.cs
index 6daeaf9..dff44e3 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/RoleQuery.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Queries/Identity/RoleQuery.cs
@@ -1,34 +1,64 @@
using Microsoft.EntityFrameworkCore;
+using NetCorePal.D3Shop.Admin.Shared.Requests;
+using NetCorePal.D3Shop.Admin.Shared.Responses;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate.Dto;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Web.Extensions;
+using NetCorePal.Extensions.Dto;
+using NetCorePal.Extensions.Primitives;
namespace NetCorePal.D3Shop.Web.Application.Queries.Identity;
-public class RoleQuery(ApplicationDbContext dbContext)
+public class RoleQuery(ApplicationDbContext dbContext) : IQuery
{
- public async Task> GetAllRolesAsync(CancellationToken cancellationToken)
+ private DbSet RoleSet { get; } = dbContext.Roles;
+
+ public async Task> GetAllRolesAsync(RoleQueryRequest query,
+ CancellationToken cancellationToken)
{
- return await dbContext.Roles.ToListAsync(cancellationToken: cancellationToken);
+ return await RoleSet
+ .WhereIf(!query.Name.IsNullOrWhiteSpace(), r => r.Name.Contains(query.Name!))
+ .WhereIf(!query.Description.IsNullOrWhiteSpace(), r => r.Description.Contains(query.Description!))
+ .Select(r => new RoleResponse(r.Id, r.Name, r.Description))
+ .ToPagedDataAsync(query, cancellationToken: cancellationToken);
}
- public async Task> GetRolesByCondition(string? name, string? description)
+ public async Task> GetAllAdminUserRolesAsync(CancellationToken cancellationToken)
{
- var queryable = dbContext.Roles.AsQueryable();
+ return await RoleSet
+ .Select(r => new AdminUserRoleResponse(r.Id, r.Name, false))
+ .ToListAsync(cancellationToken: cancellationToken);
+ }
- if (!string.IsNullOrWhiteSpace(name))
- queryable = queryable.Where(x => x.Name.Contains(name));
- if (!string.IsNullOrWhiteSpace(description))
- queryable = queryable.Where(x => x.Description.Contains(description));
+ public async Task> GetAdminRolesForAssignmentAsync(IEnumerable ids,
+ CancellationToken cancellationToken)
+ {
+ return await RoleSet
+ .Where(r => ids.Contains(r.Id))
+ .Select(r => new AssignAdminUserRoleDto(
+ r.Id,
+ r.Name,
+ r.Permissions.Select(rp =>
+ new AdminUserPermission(rp.PermissionCode, rp.PermissionRemark)))
+ )
+ .ToListAsync(cancellationToken: cancellationToken);
+ }
- return await queryable.ToListAsync();
+ public async Task> GetRolePermissionsAsync(RoleId id, CancellationToken cancellationToken)
+ {
+ return await RoleSet.Where(r => r.Id == id)
+ .SelectMany(r => r.Permissions.Select(rp => rp.PermissionCode))
+ .ToListAsync(cancellationToken);
}
- public async Task GetRoleByNameAsync(string name, CancellationToken cancellationToken)
+ public async Task RoleExistsByNameAsync(string name, CancellationToken cancellationToken)
{
- return await dbContext.Roles.FirstOrDefaultAsync(x => x.Name == name, cancellationToken);
+ return await RoleSet.AnyAsync(r => r.Name == name, cancellationToken);
}
- public async Task GetRoleByIdAsync(RoleId id, CancellationToken cancellationToken)
+ public async Task RoleExistsByNameAsync(string name, RoleId id, CancellationToken cancellationToken)
{
- return await dbContext.Roles.FindAsync([id], cancellationToken);
+ return await RoleSet.AnyAsync(r => r.Name == name && r.Id != id, cancellationToken);
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Application/Queries/OrderQuery.cs b/src/NetCorePal.D3Shop.Web/Application/Queries/OrderQuery.cs
index 9256e7c..cc2d59a 100644
--- a/src/NetCorePal.D3Shop.Web/Application/Queries/OrderQuery.cs
+++ b/src/NetCorePal.D3Shop.Web/Application/Queries/OrderQuery.cs
@@ -1,11 +1,9 @@
-using System.Threading;
-using NetCorePal.D3Shop.Domain;
-using NetCorePal.D3Shop.Domain.AggregatesModel.OrderAggregate;
-using NetCorePal.D3Shop.Infrastructure;
+using NetCorePal.D3Shop.Domain.AggregatesModel.OrderAggregate;
+using NetCorePal.Extensions.Primitives;
namespace NetCorePal.D3Shop.Web.Application.Queries
{
- public class OrderQuery(ApplicationDbContext applicationDbContext)
+ public class OrderQuery(ApplicationDbContext applicationDbContext) : IQuery
{
public async Task QueryOrder(OrderId orderId, CancellationToken cancellationToken)
{
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/BlazorServiceExtensions.cs b/src/NetCorePal.D3Shop.Web/Blazor/BlazorServiceExtensions.cs
new file mode 100644
index 0000000..0007eae
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Blazor/BlazorServiceExtensions.cs
@@ -0,0 +1,13 @@
+using NetCorePal.D3Shop.Web.Admin.Client.Services;
+using NetCorePal.D3Shop.Web.Blazor.Services;
+
+namespace NetCorePal.D3Shop.Web.Blazor;
+
+public static class BlazorServiceExtensions
+{
+ public static void AddClientServices(this IServiceCollection services)
+ {
+ services.AddScoped();
+ services.AddScoped();
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/Components/PersistingServerAuthenticationStateProvider.cs b/src/NetCorePal.D3Shop.Web/Blazor/Components/PersistingServerAuthenticationStateProvider.cs
index ce35501..c04dcdd 100644
--- a/src/NetCorePal.D3Shop.Web/Blazor/Components/PersistingServerAuthenticationStateProvider.cs
+++ b/src/NetCorePal.D3Shop.Web/Blazor/Components/PersistingServerAuthenticationStateProvider.cs
@@ -54,7 +54,8 @@ private async Task OnPersistingAsync()
if (principal.Identity?.IsAuthenticated == true)
{
var userIdString = principal.FindFirst(_options.ClaimsIdentity.UserIdClaimType)?.Value;
- if (userIdString != null)
+ var name = principal.FindFirst(_options.ClaimsIdentity.UserNameClaimType)?.Value;
+ if (userIdString != null && name != null)
{
if (!long.TryParse(userIdString, out var userId))
throw new InvalidOperationException("User Id could not be parsed to a valid long value.");
@@ -62,7 +63,7 @@ private async Task OnPersistingAsync()
_state.PersistAsJson(nameof(UserInfo), new UserInfo
{
UserId = userIdString,
- Roles = principal.FindAll(_options.ClaimsIdentity.RoleClaimType).Select(c => c.Value),
+ Name = name,
Permissions = permissions ?? []
});
}
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/ServiceExceptionHandlerAttribute.cs b/src/NetCorePal.D3Shop.Web/Blazor/ServiceExceptionHandlerAttribute.cs
new file mode 100644
index 0000000..83972fb
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Blazor/ServiceExceptionHandlerAttribute.cs
@@ -0,0 +1,29 @@
+using AntDesign;
+using NetCorePal.Extensions.Dto;
+using NetCorePal.Extensions.Primitives;
+using Rougamo;
+using Rougamo.Context;
+
+namespace NetCorePal.D3Shop.Web.Blazor;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+public class ServiceExceptionHandlerAttribute : MoAttribute
+{
+ private readonly KnownExceptionHandleMiddlewareOptions _options = new();
+
+ public override void OnException(MethodContext context)
+ {
+ if (context.Exception is IKnownException ex)
+ {
+ context.HandledException(this, new ResponseData(success: false, message: ex.Message, code: ex.ErrorCode,
+ errorData: ex.ErrorData));
+ }
+ else
+ {
+ var logger = context.GetRequiredService>();
+ logger.LogError(context.Exception, message: "{Message}", _options.UnknownExceptionMessage);
+ var messageService = context.GetRequiredService();
+ _ = messageService.Error("服务器内部异常!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/Services/AdminUserService.cs b/src/NetCorePal.D3Shop.Web/Blazor/Services/AdminUserService.cs
new file mode 100644
index 0000000..9a7c584
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Blazor/Services/AdminUserService.cs
@@ -0,0 +1,53 @@
+using NetCorePal.D3Shop.Admin.Shared.Requests;
+using NetCorePal.D3Shop.Admin.Shared.Responses;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
+using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
+using NetCorePal.D3Shop.Web.Admin.Client.Services;
+using NetCorePal.D3Shop.Web.Controllers.Identity;
+using NetCorePal.Extensions.Dto;
+
+namespace NetCorePal.D3Shop.Web.Blazor.Services;
+
+[ServiceExceptionHandler]
+public class AdminUserService(AdminUserController adminUserController) : IAdminUserService
+{
+ public Task> CreateAdminUser(CreateAdminUserRequest request)
+ {
+ return adminUserController.CreateAdminUser(request);
+ }
+
+ public Task>> GetAllAdminUsers(AdminUserQueryRequest request)
+ {
+ return adminUserController.GetAllAdminUsers(request);
+ }
+
+ public Task>> GetAdminUserRoles(AdminUserId id)
+ {
+ return adminUserController.GetAdminUserRoles(id);
+ }
+
+ public Task UpdateAdminUserRoles(AdminUserId id, IEnumerable roleIds)
+ {
+ return adminUserController.UpdateAdminUserRoles(id, roleIds);
+ }
+
+ public Task DeleteAdminUser(AdminUserId id)
+ {
+ return adminUserController.DeleteAdminUser(id);
+ }
+
+ public Task>> GetAllRolesForCreateUser()
+ {
+ return adminUserController.GetAllRolesForCreateUser();
+ }
+
+ public Task>> GetAdminUserPermissions(AdminUserId id)
+ {
+ return adminUserController.GetAdminUserPermissions(id);
+ }
+
+ public Task SetAdminUserSpecificPermissions(AdminUserId id, IEnumerable permissionCodes)
+ {
+ return adminUserController.SetAdminUserSpecificPermissions(id, permissionCodes);
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/Services/PermissionsService.cs b/src/NetCorePal.D3Shop.Web/Blazor/Services/PermissionsService.cs
deleted file mode 100644
index a1a0f75..0000000
--- a/src/NetCorePal.D3Shop.Web/Blazor/Services/PermissionsService.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission;
-using NetCorePal.D3Shop.Web.Admin.Client.Services;
-using NetCorePal.Extensions.Dto;
-
-namespace NetCorePal.D3Shop.Web.Blazor.Services;
-
-public class PermissionsService : IPermissionsService
-{
- public Task>> GetAll()
- {
- IEnumerable permissions = Permissions.AllPermissions;
- return Task.FromResult(permissions.AsResponseData());
- }
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Blazor/Services/RolesService.cs b/src/NetCorePal.D3Shop.Web/Blazor/Services/RolesService.cs
index b2a946c..bfe8547 100644
--- a/src/NetCorePal.D3Shop.Web/Blazor/Services/RolesService.cs
+++ b/src/NetCorePal.D3Shop.Web/Blazor/Services/RolesService.cs
@@ -7,47 +7,41 @@
namespace NetCorePal.D3Shop.Web.Blazor.Services;
+[ServiceExceptionHandler]
public class RolesService(RoleController roleController) : IRolesService
{
- public async Task> CreateRole(CreateRoleRequest request)
+ public Task> CreateRole(CreateRoleRequest request)
{
- return await roleController.CreateRole(request);
+ return roleController.CreateRole(request);
}
- public async Task>> GetAllRoles()
+ public Task>> GetAllRoles(RoleQueryRequest request)
{
- return await roleController.GetAllRoles();
+ return roleController.GetAllRoles(request);
}
- public async Task UpdateRoleInfo(RoleId id, UpdateRoleInfoRequest request)
+ public Task UpdateRoleInfo(RoleId id, UpdateRoleInfoRequest request)
{
- return await roleController.UpdateRoleInfo(id, request);
+ return roleController.UpdateRoleInfo(id, request);
}
- public async Task UpdateRolePermissions(RoleId id, List permissionCodes)
+ public Task UpdateRolePermissions(RoleId id, List permissionCodes)
{
- return await roleController.UpdateRolePermissions(id, permissionCodes);
+ return roleController.UpdateRolePermissions(id, permissionCodes);
}
- public async Task DeleteRole(RoleId id)
+ public Task DeleteRole(RoleId id)
{
- return await roleController.DeleteRole(id);
+ return roleController.DeleteRole(id);
}
- public async Task>> GetRolesByCondition(
- RoleQueryRequest request)
+ public Task>> GetRolePermissions(RoleId id)
{
- return await roleController.GetRolesByCondition(request);
+ return roleController.GetRolePermissions(id);
}
- public async Task> GetRoleById(RoleId id)
+ public Task>> GetAllPermissionsForCreateRole()
{
- return await roleController.GetRoleById(id);
- }
-
- public async Task>>
- GetRolePermissions(RoleId id)
- {
- return await roleController.GetRolePermissions(id);
+ return roleController.GetAllPermissionsForCreateRole();
}
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserAccountController.cs b/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserAccountController.cs
index 4f15163..dff5f33 100644
--- a/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserAccountController.cs
+++ b/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserAccountController.cs
@@ -4,10 +4,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
-using NetCorePal.D3Shop.Admin.Shared.Const;
using NetCorePal.D3Shop.Admin.Shared.Requests;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using NetCorePal.D3Shop.Web.Application.Queries.Identity;
+using NetCorePal.D3Shop.Web.Application.Queries.Identity.QueryResult;
using NetCorePal.D3Shop.Web.Helper;
using NetCorePal.Extensions.Dto;
using NetCorePal.Extensions.Primitives;
@@ -26,7 +25,7 @@ public class AdminUserAccountController(
[HttpPost("login")]
public async Task LoginAsync([FromBody] AdminUserLoginRequest request)
{
- var user = await adminUserQuery.GetAdminUserByNameAsync(request.Name, HttpContext.RequestAborted);
+ var user = await adminUserQuery.GetUserInfoForLoginAsync(request.Name, HttpContext.RequestAborted);
if (user is null)
throw new KnownException("Invalid Credentials.");
@@ -49,78 +48,15 @@ await HttpContext.SignInAsync(
return new ResponseData();
}
- private static IEnumerable GetClaimsAsync(AdminUser user)
+ private static List GetClaimsAsync(AuthenticationUserInfo user)
{
- var roles = user.Roles;
- var roleClaims = roles.Select(role => new Claim(ClaimTypes.Role, role.RoleName)).ToList();
- //系统默认用户添加超级管理员角色
- if (user.Name == AppDefaultCredentials.Name)
- roleClaims.Add(new Claim(ClaimTypes.Role, AppClaim.SuperAdminRole));
-
var claims = new List
{
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
new(ClaimTypes.Name, user.Name),
new(ClaimTypes.MobilePhone, user.Phone)
- }
- .Union(roleClaims);
+ };
return claims;
}
-
-
- /*private static string GenerateRefreshToken()
- {
- var randomNumber = new byte[32];
- using var rnd = RandomNumberGenerator.Create();
- rnd.GetBytes(randomNumber);
-
- return Convert.ToBase64String(randomNumber);
- }
-
- private string GenerateJwtAsync(AdminUser user)
- {
- var token = GenerateEncryptedToken(GetSigningCredentials(), GetClaimsAsync(user));
- return token;
- }
-
- private string GenerateEncryptedToken(SigningCredentials signingCredentials, IEnumerable claims)
- {
- var token = new JwtSecurityToken(
- claims: claims,
- expires: DateTime.UtcNow.AddMinutes(AppConfiguration.TokenExpiryInMinutes),
- signingCredentials: signingCredentials);
- var tokenHandler = new JwtSecurityTokenHandler();
- var encryptedToken = tokenHandler.WriteToken(token);
- return encryptedToken;
- }
-
- private SigningCredentials GetSigningCredentials()
- {
- var secret = Encoding.UTF8.GetBytes(AppConfiguration.Secret);
- return new SigningCredentials(new SymmetricSecurityKey(secret), SecurityAlgorithms.HmacSha256);
- }
-
- private ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
- {
- var tokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppConfiguration.Secret)),
- ValidateIssuer = false,
- ValidateAudience = false,
- RoleClaimType = ClaimTypes.Role,
- ClockSkew = TimeSpan.Zero
- };
- var tokenHandler = new JwtSecurityTokenHandler();
- var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);
- if (securityToken is not JwtSecurityToken jwtSecurityToken
- || !jwtSecurityToken.Header.Alg
- .Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
- {
- throw new SecurityTokenException("Invalid token");
- }
-
- return principal;
- }*/
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserController.cs b/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserController.cs
index 6670e04..33e2918 100644
--- a/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserController.cs
+++ b/src/NetCorePal.D3Shop.Web/Controllers/Identity/AdminUserController.cs
@@ -3,7 +3,6 @@
using NetCorePal.D3Shop.Admin.Shared.Requests;
using NetCorePal.D3Shop.Admin.Shared.Responses;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate.Dto;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
using NetCorePal.D3Shop.Web.Application.Commands.Identity;
@@ -11,81 +10,83 @@
using NetCorePal.D3Shop.Web.Auth;
using NetCorePal.D3Shop.Web.Helper;
using NetCorePal.Extensions.Dto;
-using NetCorePal.Extensions.Mappers;
using NetCorePal.Extensions.Primitives;
namespace NetCorePal.D3Shop.Web.Controllers.Identity;
[Route("api/[controller]/[action]")]
[ApiController]
-public class AdminUserController(IMediator mediator, IMapperProvider mapperProvider, AdminUserQuery adminUserQuery, RoleQuery roleQuery)
+[AdminPermission(PermissionDefinitions.AdminUserView)]
+public class AdminUserController(
+ IMediator mediator,
+ AdminUserQuery adminUserQuery,
+ RoleQuery roleQuery)
: ControllerBase
{
- private CancellationToken CancellationToken => HttpContext.RequestAborted;
- private IMapper AdminUserOutputMapper => mapperProvider.GetMapper();
+ private CancellationToken CancellationToken => HttpContext?.RequestAborted ?? default;
[HttpPost]
[AdminPermission(PermissionDefinitions.AdminUserCreate)]
public async Task> CreateAdminUser([FromBody] CreateAdminUserRequest request)
{
- var roles = await roleQuery.GetAllRolesAsync(CancellationToken);
- var rolesToBeAssigned = roles.Where(r => request.RoleIds.Contains(r.Id))
- .Select(r => new AssignAdminUserRoleDto(
- r.Id,
- r.Name,
- r.Permissions.Select(rp =>
- new AdminUserPermission(rp.PermissionCode, rp.PermissionRemark)))
- );
+ var rolesToBeAssigned = await roleQuery.GetAdminRolesForAssignmentAsync(request.RoleIds, CancellationToken);
var password = PasswordHasher.HashPassword(request.PassWord);
var adminUserId = await mediator.Send(
new CreateAdminUserCommand(request.Name, request.Phone, password, rolesToBeAssigned),
- CancellationToken);
+ CancellationToken);
return adminUserId.AsResponseData();
}
[HttpGet]
- [AdminPermission(PermissionDefinitions.AdminUserView)]
- public async Task>> GetAllAdminUsers()
+ public async Task>> GetAllAdminUsers(
+ [FromQuery] AdminUserQueryRequest request)
{
- var adminUsers = await adminUserQuery.GetAllAdminUsersAsync(CancellationToken);
- var responses = adminUsers.Select(AdminUserOutputMapper.To);
- return responses.AsResponseData();
+ var adminUsers = await adminUserQuery.GetAllAdminUsersAsync(request, CancellationToken);
+ return adminUsers.AsResponseData();
}
- [HttpGet]
- [AdminPermission(PermissionDefinitions.AdminUserView)]
- public async Task>> GetAdminUsersByCondition([FromQuery] AdminUserQueryRequest request)
+ [HttpGet("{id}")]
+ public async Task>> GetAdminUserRoles([FromRoute] AdminUserId id)
{
- var adminUsers = await adminUserQuery.GetAdminUsersByCondition(request.Name, request.Phone);
- var responses = adminUsers.Select(AdminUserOutputMapper.To);
- return responses.AsResponseData();
+ var allRoles = await roleQuery.GetAllAdminUserRolesAsync(CancellationToken);
+ var assignedRoleIds = await adminUserQuery.GetAssignedRoleIdsAsync(id, CancellationToken);
+ var response = allRoles.Select(r =>
+ {
+ if (assignedRoleIds.Contains(r.RoleId))
+ r.IsAssigned = true;
+ return r;
+ }).ToList();
+ return response.AsResponseData();
}
[HttpGet("{id}")]
- [AdminPermission(PermissionDefinitions.AdminUserView)]
- public async Task> GetAdminUserById([FromRoute] AdminUserId id)
+ public async Task>> GetAdminUserPermissions(
+ [FromRoute] AdminUserId id)
{
- var adminUser = await adminUserQuery.GetAdminUserByIdAsync(id, CancellationToken) ??
- throw new KnownException($"该用户不存在,AdminUserId={id}");
-
- return AdminUserOutputMapper.To(adminUser).AsResponseData();
+ var allPermissions = Permissions.AllPermissions;
+ var assignedPermissions = await adminUserQuery.GetAssignedPermissionsAsync(id, CancellationToken);
+ var response = allPermissions.Select(p =>
+ {
+ var assigned = assignedPermissions.Find(ap => ap.PermissionCode == p.Code);
+ var isAssigned = assigned is not null;
+ var isFromRole = assigned?.SourceRoleIds.Count > 0;
+ return new AdminUserPermissionResponse(p.Code, p.GroupName, p.Remark, isAssigned, isFromRole);
+ }
+ ).ToList();
+ return response.AsResponseData();
}
- [HttpGet("{id}")]
- [AdminPermission(PermissionDefinitions.AdminUserView)]
- public async Task>> GetAdminUserRoles([FromRoute] AdminUserId id)
+ [HttpPut("{id}")]
+ public async Task SetAdminUserSpecificPermissions(AdminUserId id,
+ [FromBody] IEnumerable permissionCodes)
{
- var adminUser = await adminUserQuery.GetAdminUserByIdAsync(id, CancellationToken);
- if (adminUser is null) throw new KnownException($"该用户不存在,AdminUserId={id}");
-
- var allRoles = await roleQuery.GetAllRolesAsync(CancellationToken);
- var responses = allRoles.Select(role => adminUser.IsInRole(role.Name)
- ? new AdminUserRolesResponse(role.Id, role.Name, role.Description, false)
- : new AdminUserRolesResponse(role.Id, role.Name, role.Description, true));
-
- return responses.AsResponseData();
+ var allPermissions = Permissions.AllPermissions;
+ var permissionsToBeAssigned = allPermissions.Where(x => permissionCodes.Contains(x.Code))
+ .Select(p => new AdminUserPermission(p.Code, p.Remark));
+ await mediator.Send(new SetAdminUserSpecificPermissions(id, permissionsToBeAssigned), CancellationToken);
+ return new ResponseData();
}
[HttpPut("{id}")]
@@ -93,7 +94,7 @@ public async Task>> GetAdminUse
public async Task ChangeAdminUserPassword([FromRoute] AdminUserId id,
[FromBody] UpdateAdminUserPasswordRequest request)
{
- var adminUser = await adminUserQuery.GetAdminUserByIdAsync(id, CancellationToken);
+ var adminUser = await adminUserQuery.GetUserCredentialsIfExists(id, CancellationToken);
if (adminUser is null) throw new KnownException($"该用户不存在,AdminUserId = {id}");
if (!PasswordHasher.VerifyHashedPassword(adminUser.Password, request.OldPassword))
@@ -106,16 +107,10 @@ public async Task ChangeAdminUserPassword([FromRoute] AdminUserId
[HttpPut("{id}")]
[AdminPermission(PermissionDefinitions.AdminUserUpdateRoles)]
- public async Task UpdateAdminUserRoles([FromRoute] AdminUserId id, [FromBody] IEnumerable roleIds)
+ public async Task UpdateAdminUserRoles([FromRoute] AdminUserId id,
+ [FromBody] IEnumerable roleIds)
{
- var allRoles = await roleQuery.GetAllRolesAsync(CancellationToken);
- var rolesToBeAssigned = allRoles.Where(r => roleIds.Contains(r.Id))
- .Select(r =>
- new AssignAdminUserRoleDto(r.Id, r.Name,
- r.Permissions.Select(p =>
- new AdminUserPermission(p.PermissionCode, p.PermissionRemark))
- )).ToList();
-
+ var rolesToBeAssigned = await roleQuery.GetAdminRolesForAssignmentAsync(roleIds, CancellationToken);
await mediator.Send(new UpdateAdminUserRolesCommand(id, rolesToBeAssigned), CancellationToken);
return new ResponseData();
}
@@ -127,4 +122,11 @@ public async Task DeleteAdminUser([FromRoute] AdminUserId id)
await mediator.Send(new DeleteAdminUserCommand(id), CancellationToken);
return new ResponseData();
}
+
+ [HttpGet]
+ public async Task>> GetAllRolesForCreateUser()
+ {
+ var roles = await roleQuery.GetAllAdminUserRolesAsync(CancellationToken);
+ return roles.AsResponseData();
+ }
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Controllers/Identity/PermissionController.cs b/src/NetCorePal.D3Shop.Web/Controllers/Identity/PermissionController.cs
deleted file mode 100644
index a57717c..0000000
--- a/src/NetCorePal.D3Shop.Web/Controllers/Identity/PermissionController.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.Permission;
-using NetCorePal.Extensions.Dto;
-
-namespace NetCorePal.D3Shop.Web.Controllers.Identity;
-
-[Route("api/[controller]/[action]")]
-[ApiController]
-public class PermissionController
-{
- [HttpGet]
- public Task>> GetAll()
- {
- IEnumerable permissions = Permissions.AllPermissions;
-
- return Task.FromResult(permissions.AsResponseData());
- }
-}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Controllers/Identity/RoleController.cs b/src/NetCorePal.D3Shop.Web/Controllers/Identity/RoleController.cs
index 1b42541..a84ccd3 100644
--- a/src/NetCorePal.D3Shop.Web/Controllers/Identity/RoleController.cs
+++ b/src/NetCorePal.D3Shop.Web/Controllers/Identity/RoleController.cs
@@ -8,19 +8,15 @@
using NetCorePal.D3Shop.Web.Application.Queries.Identity;
using NetCorePal.D3Shop.Web.Auth;
using NetCorePal.Extensions.Dto;
-using NetCorePal.Extensions.Mappers;
-using NetCorePal.Extensions.Primitives;
namespace NetCorePal.D3Shop.Web.Controllers.Identity;
[Route("api/[controller]/[action]")]
[ApiController]
-public class RoleController(IMediator mediator, IMapperProvider mapperProvider, RoleQuery roleQuery) : ControllerBase
+public class RoleController(IMediator mediator, RoleQuery roleQuery) : ControllerBase
{
private CancellationToken CancellationToken => HttpContext?.RequestAborted ?? CancellationToken.None;
- private IMapper RoleOutputMapper => mapperProvider.GetMapper();
-
[HttpPost]
[AdminPermission(PermissionDefinitions.RoleCreate)]
public async Task> CreateRole([FromBody] CreateRoleRequest request)
@@ -38,46 +34,23 @@ public async Task> CreateRole([FromBody] CreateRoleRequest
[HttpGet]
[AdminPermission(PermissionDefinitions.RoleView)]
- public async Task>> GetAllRoles()
- {
- var roles = await roleQuery.GetAllRolesAsync(CancellationToken);
- var response = roles.Select(RoleOutputMapper.To);
- return response.AsResponseData();
- }
-
- [HttpGet]
- [AdminPermission(PermissionDefinitions.RoleView)]
- public async Task>> GetRolesByCondition([FromQuery] RoleQueryRequest request)
- {
- var roles = await roleQuery.GetRolesByCondition(request.Name, request.Description);
- var response = roles.Select(RoleOutputMapper.To);
- return response.AsResponseData();
- }
-
- [HttpGet("{id}")]
- [AdminPermission(PermissionDefinitions.RoleView)]
- public async Task> GetRoleById([FromRoute] RoleId id)
+ public async Task>> GetAllRoles([FromQuery] RoleQueryRequest request)
{
- var role = await roleQuery.GetRoleByIdAsync(id, CancellationToken);
- if (role == null) throw new KnownException($"未找到角色,RoleId = {id}");
-
- return RoleOutputMapper.To(role).AsResponseData();
+ var roles = await roleQuery.GetAllRolesAsync(request, CancellationToken);
+ return roles.AsResponseData();
}
[HttpGet("{id}")]
[AdminPermission(PermissionDefinitions.RoleView)]
- public async Task>> GetRolePermissions([FromRoute] RoleId id)
+ public async Task>> GetRolePermissions([FromRoute] RoleId id)
{
- var role = await roleQuery.GetRoleByIdAsync(id, CancellationToken);
- if (role == null) throw new KnownException($"未找到角色,RoleId = {id}");
-
var allPermissions = Permissions.AllPermissions;
- var rolePermissionCodes = role.Permissions.Select(x => x.PermissionCode);
-
+ var rolePermissions = await roleQuery.GetRolePermissionsAsync(id, CancellationToken);
var response = allPermissions.Select(p =>
- rolePermissionCodes.Contains(p.Code)
- ? new RolePermissionResponse(p.Code, p.Remark, p.GroupName, true)
- : new RolePermissionResponse(p.Code, p.Remark, p.GroupName, false));
+ rolePermissions.Contains(p.Code)
+ ? new RolePermissionResponse(p.Code, p.GroupName, p.Remark, true)
+ : new RolePermissionResponse(p.Code, p.GroupName, p.Remark, false))
+ .ToList();
return response.AsResponseData();
}
@@ -114,4 +87,12 @@ public async Task DeleteRole([FromRoute] RoleId id)
await mediator.Send(new DeleteRoleCommand(id), CancellationToken);
return new ResponseData();
}
+
+ [HttpGet]
+ public Task>> GetAllPermissionsForCreateRole()
+ {
+ IEnumerable permissions = Permissions.AllPermissions;
+ var response = permissions.Select(p => new RolePermissionResponse(p.Code, p.GroupName, p.Remark, false));
+ return Task.FromResult(response.AsResponseData());
+ }
}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Extensions/QueryableExtensions.cs b/src/NetCorePal.D3Shop.Web/Extensions/QueryableExtensions.cs
new file mode 100644
index 0000000..3ff9e3f
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Extensions/QueryableExtensions.cs
@@ -0,0 +1,40 @@
+using System.Linq.Expressions;
+
+namespace NetCorePal.D3Shop.Web.Extensions;
+
+///
+/// 一些针对 的实用扩展方法。
+///
+public static class QueryableExtensions
+{
+
+ /*///
+ /// 根据指定的条件,在 上应用筛选操作。
+ ///
+ /// 要应用筛选的 IQueryable
+ /// 一个布尔值,决定是否应用筛选
+ /// 用于筛选的条件表达式
+ /// 根据 返回已筛选或未筛选的查询
+ public static IQueryable WhereIf(this IQueryable query, bool condition,
+ Expression> predicate)
+ {
+ return condition
+ ? query.Where(predicate)
+ : query;
+ }*/
+
+ ///
+ /// 根据指定的条件,在 上应用筛选操作。
+ ///
+ /// 要应用筛选的 IQueryable
+ /// 一个布尔值,决定是否应用筛选
+ /// 用于筛选的条件表达式
+ /// 根据 返回已筛选或未筛选的查询
+ public static IQueryable WhereIf(this IQueryable query, bool condition,
+ Expression> predicate)
+ {
+ return condition
+ ? query.Where(predicate)
+ : query;
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/Extensions/StringExtensions.cs b/src/NetCorePal.D3Shop.Web/Extensions/StringExtensions.cs
new file mode 100644
index 0000000..824f093
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/Extensions/StringExtensions.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace NetCorePal.D3Shop.Web.Extensions;
+
+///
+/// 一些针对 string 的实用扩展方法。
+///
+public static class StringExtensions
+{
+ ///
+ /// 提供对 的简化使用,用于判断字符串是否为 null、空字符串或仅包含空白字符。
+ ///
+ /// 要检查的字符串。
+ ///
+ /// 如果字符串为 null、空字符串或仅包含空白字符,则返回 true ;否则返回 false 。
+ ///
+ public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? str)
+ {
+ return string.IsNullOrWhiteSpace(str);
+ }
+}
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/FodyWeavers.xml b/src/NetCorePal.D3Shop.Web/FodyWeavers.xml
new file mode 100644
index 0000000..a6a2edf
--- /dev/null
+++ b/src/NetCorePal.D3Shop.Web/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/NetCorePal.D3Shop.Web/NetCorePal.D3Shop.Web.csproj b/src/NetCorePal.D3Shop.Web/NetCorePal.D3Shop.Web.csproj
index 8c3b9dc..c80a73b 100644
--- a/src/NetCorePal.D3Shop.Web/NetCorePal.D3Shop.Web.csproj
+++ b/src/NetCorePal.D3Shop.Web/NetCorePal.D3Shop.Web.csproj
@@ -12,6 +12,7 @@
+
@@ -41,13 +42,14 @@
+
+
-
diff --git a/src/NetCorePal.D3Shop.Web/Program.cs b/src/NetCorePal.D3Shop.Web/Program.cs
index 5bddee6..b05e9e3 100644
--- a/src/NetCorePal.D3Shop.Web/Program.cs
+++ b/src/NetCorePal.D3Shop.Web/Program.cs
@@ -9,19 +9,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using NetCorePal.D3Shop.Admin.Shared.Authorization;
-using NetCorePal.D3Shop.Web.Admin.Client.Services;
+using NetCorePal.D3Shop.Web.Admin.Client.Auth;
using NetCorePal.D3Shop.Web.Application.Hubs;
using NetCorePal.D3Shop.Web.Application.IntegrationEventHandlers;
-using NetCorePal.D3Shop.Web.Application.Queries;
-using NetCorePal.D3Shop.Web.Application.Queries.Identity;
using NetCorePal.D3Shop.Web.Auth;
+using NetCorePal.D3Shop.Web.Blazor;
using NetCorePal.D3Shop.Web.Blazor.Components;
-using NetCorePal.D3Shop.Web.Blazor.Services;
using NetCorePal.D3Shop.Web.Clients;
using NetCorePal.D3Shop.Web.Extensions;
-using NetCorePal.Extensions.AspNetCore.Json;
using NetCorePal.Extensions.Domain.Json;
using NetCorePal.Extensions.MultiEnv;
+using NetCorePal.Extensions.NewtonsoftJson;
using NetCorePal.Extensions.Primitives;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@@ -119,9 +117,7 @@
#region Query
- builder.Services.AddScoped();
- builder.Services.AddScoped();
- builder.Services.AddScoped();
+ builder.Services.AddAllQueries(Assembly.GetExecutingAssembly());
#endregion
@@ -149,8 +145,7 @@
builder.Services.AddIntegrationEventServices(typeof(Program))
.AddIIntegrationEventConverter(typeof(Program))
.UseCap(typeof(Program))
- .AddContextIntegrationFilters()
- .AddEnvIntegrationFilters(_ => { });
+ .AddContextIntegrationFilters();
builder.Services.AddCap(x =>
{
x.UseEntityFramework();
@@ -201,9 +196,10 @@
builder.Services.AddAntDesign();
builder.Services.AddCascadingAuthenticationState();
+ builder.Services.AddSingleton();
builder.Services.AddScoped();
- builder.Services.AddScoped();
- builder.Services.AddScoped();
+
+ builder.Services.AddClientServices();
#endregion
@@ -241,7 +237,7 @@
app.UseHttpMetrics();
app.MapHealthChecks("/health");
- app.MapMetrics("/metrics"); // 通过 /metrics 访问指标
+ app.MapMetrics(); // 通过 /metrics 访问指标
app.UseHangfireDashboard();
app.MapRazorComponents()
.AddInteractiveServerRenderMode()
diff --git a/test/NetCorePal.D3Shop.Web.Tests/Identity/AdminUserRoleIntegrationTests.cs b/test/NetCorePal.D3Shop.Web.Tests/Identity/AdminUserRoleIntegrationTests.cs
index c6114f6..510b444 100644
--- a/test/NetCorePal.D3Shop.Web.Tests/Identity/AdminUserRoleIntegrationTests.cs
+++ b/test/NetCorePal.D3Shop.Web.Tests/Identity/AdminUserRoleIntegrationTests.cs
@@ -13,6 +13,7 @@ namespace NetCorePal.D3Shop.Web.Tests.Identity;
public class AdminUserRoleIntegrationTests
{
private readonly HttpClient _client;
+
public AdminUserRoleIntegrationTests(MyWebApplicationFactory factory)
{
_client = factory.WithWebHostBuilder(builder => { builder.ConfigureServices(_ => { }); })
@@ -24,7 +25,7 @@ public AdminUserRoleIntegrationTests(MyWebApplicationFactory factory)
}
""";
var content = new StringContent(json);
- content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
+ content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
_client.PostAsync("api/AdminUserAccount/login", content).GetAwaiter().GetResult();
}
@@ -37,10 +38,17 @@ public AdminUserRoleIntegrationTests(MyWebApplicationFactory factory)
private async Task CreateTestAdminUser(string name, IEnumerable roleIds)
{
// Arrange
- var createAdminUserRequest = new CreateAdminUserRequest(name, "1", "123", roleIds);
+ var createAdminUserRequest = new CreateAdminUserRequest
+ {
+ Name = name,
+ PassWord = "123",
+ Phone = "1",
+ RoleIds = roleIds
+ };
// Act - 期望用户创建成功
- var response = await _client.PostAsNewtonsoftJsonAsync("/api/AdminUser/CreateAdminUser", createAdminUserRequest);
+ var response =
+ await _client.PostAsNewtonsoftJsonAsync("/api/AdminUser/CreateAdminUser", createAdminUserRequest);
// Assert - 创建成功
Assert.True(response.IsSuccessStatusCode);
@@ -58,30 +66,25 @@ private async Task CreateTestAdminUser(string name, IEnumerable>>();
+ var allUsersData = await allUsersResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>();
Assert.NotNull(allUsersData);
- Assert.NotEmpty(allUsersData.Data); // 验证返回的用户列表不为空
+ Assert.NotEmpty(allUsersData.Data.Items); // 验证返回的用户列表不为空
// Act 3: Get admin users by condition
- var conditionResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUsersByCondition?Name={testUserName}");
+ var conditionResponse = await _client.GetAsync($"/api/AdminUser/GetAllAdminUsers?Name={testUserName}&PageIndex=1");
conditionResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
- var conditionData = await conditionResponse.Content.ReadFromNewtonsoftJsonAsync>>();
+ var conditionData = await conditionResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>();
Assert.NotNull(conditionData);
- Assert.All(conditionData.Data, user => Assert.Contains(testUserName, user.Name)); // 验证返回的用户符合条件
-
- // Act 4: Get the created user by ID
- var getUserResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserById/{testUserId.Id}");
- getUserResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
- var getUserData = await getUserResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(getUserData);
- Assert.Equal(testUserId, getUserData.Data.Id); // 验证返回的用户 ID 符合请求
+ Assert.All(conditionData.Data.Items, user => Assert.Contains(testUserName, user.Name)); // 验证返回的用户符合条件
}
///
@@ -91,10 +94,12 @@ public async Task CreateAdminUser_And_QueryAdminUserByVariousMethods_ShouldSucce
///
///
///
- private async Task CreateTestRoleAsync(string roleName, string roleDescription, IEnumerable permissionCodes)
+ private async Task CreateTestRoleAsync(string roleName, string roleDescription,
+ IEnumerable permissionCodes)
{
// Arrange
- var createRoleRequest = new CreateRoleRequest(roleName, roleDescription, permissionCodes);
+ var createRoleRequest = new CreateRoleRequest
+ { Name = roleName, Description = roleDescription, PermissionCodes = permissionCodes };
// Act
var response = await _client.PostAsJsonAsync("api/Role/CreateRole", createRoleRequest);
@@ -122,27 +127,46 @@ public async Task UpdateAdminUserRoles_ShouldUpdateRolesSuccessfully()
var testUserId = await CreateTestAdminUser(testUserName, [roleId]);
// Step 3: 验证用户初始角色和权限
- var getUserDataResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserById/{testUserId}");
- getUserDataResponse.EnsureSuccessStatusCode();
- var userData = await getUserDataResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(userData);
- Assert.Equal(roleId, userData.Data.Roles.Single().RoleId);
- Assert.Equal(permissionCodes.OrderBy(p => p), userData.Data.Permissions.Select(p => p.PermissionCode).OrderBy(p => p));
+ var getAdminUserRolesResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserRoles/{testUserId}");
+ getAdminUserRolesResponse.EnsureSuccessStatusCode();
+ var adminUserRoles = (
+ await getAdminUserRolesResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(adminUserRoles);
+ Assert.Equal(roleId, adminUserRoles.Single(r => r.IsAssigned).RoleId);
+ var getAdminUserPermissionsResponse =
+ await _client.GetAsync($"/api/AdminUser/GetAdminUserPermissions/{testUserId}");
+ var adminUserPermissions =
+ (await getAdminUserPermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(adminUserPermissions);
+ Assert.Equal(permissionCodes.OrderBy(p => p),
+ adminUserPermissions.Where(aup => aup.IsAssigned).Select(p => p.Code).OrderBy(p => p));
// Step 4: 更新用户角色
permissionCodes = Permissions.AllPermissions.TakeLast(2).Select(p => p.Code).ToList();
var newRoleId = await CreateTestRoleAsync("NewTestRole", "Description of the new test role", permissionCodes);
- var updateResponse = await _client.PutAsNewtonsoftJsonAsync($"/api/adminUser/UpdateAdminUserRoles/{testUserId}", new List { newRoleId });
+ var updateResponse = await _client.PutAsNewtonsoftJsonAsync($"/api/adminUser/UpdateAdminUserRoles/{testUserId}",
+ new List { newRoleId });
updateResponse.EnsureSuccessStatusCode();
// Step 5: 验证用户更新后的角色和权限
- getUserDataResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserById/{testUserId}");
- getUserDataResponse.EnsureSuccessStatusCode();
- userData = await getUserDataResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(userData);
- Assert.Equal(newRoleId, userData.Data.Roles.Single().RoleId);
- Assert.Equal(permissionCodes.OrderBy(p => p), userData.Data.Permissions.Select(p => p.PermissionCode).OrderBy(p => p));// 验证权限
+ getAdminUserRolesResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserRoles/{testUserId}");
+ getAdminUserRolesResponse.EnsureSuccessStatusCode();
+ adminUserRoles =
+ (await getAdminUserRolesResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(adminUserRoles);
+ Assert.Equal(newRoleId, adminUserRoles.Single(r => r.IsAssigned).RoleId);
+ getAdminUserPermissionsResponse =
+ await _client.GetAsync($"/api/AdminUser/GetAdminUserPermissions/{testUserId}");
+ adminUserPermissions =
+ (await getAdminUserPermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(adminUserPermissions);
+ Assert.Equal(permissionCodes.OrderBy(p => p),
+ adminUserPermissions.Where(p => p.IsAssigned).Select(p => p.Code).OrderBy(p => p));
}
///
@@ -154,27 +178,23 @@ public async Task CreateRole_And_QueryAdminUserByVariousMethods_ShouldSucceed()
{
await CreateTestRoleAsync("defaultRole", "defaultRole", []);
- var testRoleName = "TestQueryRole";
- var testRoleId = await CreateTestRoleAsync(testRoleName, "Test role", []);
+ const string testRoleName = "TestQueryRole";
+ await CreateTestRoleAsync(testRoleName, "Test role", []);
- var allRolesResponse = await _client.GetAsync("/api/Role/GetAllRoles");
+ var allRolesResponse = await _client.GetAsync("/api/Role/GetAllRoles?PageIndex=1");
allRolesResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
- var allRolesData = await allRolesResponse.Content.ReadFromNewtonsoftJsonAsync>>();
+ var allRolesData = await allRolesResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>();
Assert.NotNull(allRolesData);
- Assert.NotEmpty(allRolesData.Data); // 验证返回的角色列表不为空
+ Assert.NotEmpty(allRolesData.Data.Items); // 验证返回的角色列表不为空
- var conditionResponse = await _client.GetAsync($"/api/Role/GetRolesByCondition?Name={testRoleName}");
+ var conditionResponse = await _client.GetAsync($"/api/Role/GetAllRoles?Name={testRoleName}&PageIndex=1");
conditionResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
- var conditionData = await conditionResponse.Content.ReadFromNewtonsoftJsonAsync>>();
+ var conditionData = await conditionResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>();
Assert.NotNull(conditionData);
- Assert.All(conditionData.Data, r => Assert.Contains(testRoleName, r.Name)); // 验证返回的用户符合条件
-
- var getRoleResponse = await _client.GetAsync($"/api/Role/GetRoleById/{testRoleId.Id}");
- getRoleResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
- var roleData = await getRoleResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(roleData);
- Assert.Equal(testRoleId, roleData.Data.Id);
+ Assert.All(conditionData.Data.Items, r => Assert.Contains(testRoleName, r.Name)); // 验证返回的用户符合条件
}
///
@@ -187,28 +207,74 @@ public async Task UpdateRolePermission_Test()
var permissionCodes = Permissions.AllPermissions.Take(2).Select(p => p.Code).ToList();
var testRoleId = await CreateTestRoleAsync("TestUpdatePermissionRole", "", permissionCodes);
var testUserId = await CreateTestAdminUser("TestUpdateRolePermissionsUser", [testRoleId]);
+ await CreateTestAdminUser("TestUpdateRolePermissionsUser2", [testRoleId]);
- var getRoleResponse = await _client.GetAsync($"api/Role/GetRoleById/{testRoleId}");
- getRoleResponse.EnsureSuccessStatusCode();
- var roleData = await getRoleResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(roleData);
- Assert.Equal(permissionCodes.OrderBy(p => p), roleData.Data.PermissionCodes.OrderBy(p => p));
+ var getRolePermissionsResponse = await _client.GetAsync($"api/Role/GetRolePermissions/{testRoleId}");
+ getRolePermissionsResponse.EnsureSuccessStatusCode();
+ var rolePermissions = (await getRolePermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(rolePermissions);
+ Assert.Equal(permissionCodes.OrderBy(p => p),
+ rolePermissions.Where(rp => rp.IsAssigned).Select(rp => rp.Code).OrderBy(p => p));
permissionCodes = Permissions.AllPermissions.TakeLast(2).Select(p => p.Code).ToList();
- var updateResponse = await _client.PutAsNewtonsoftJsonAsync($"/api/Role/UpdateRolePermissions/{testRoleId}", permissionCodes);
+ var updateResponse =
+ await _client.PutAsNewtonsoftJsonAsync($"/api/Role/UpdateRolePermissions/{testRoleId}", permissionCodes);
updateResponse.EnsureSuccessStatusCode();
- getRoleResponse = await _client.GetAsync($"api/Role/GetRoleById/{testRoleId}");
- getRoleResponse.EnsureSuccessStatusCode();
- roleData = await getRoleResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(roleData);
- Assert.Equal(permissionCodes.OrderBy(p => p), roleData.Data.PermissionCodes.OrderBy(p => p));
+ getRolePermissionsResponse = await _client.GetAsync($"api/Role/GetRolePermissions/{testRoleId}");
+ getRolePermissionsResponse.EnsureSuccessStatusCode();
+ rolePermissions =
+ (await getRolePermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(rolePermissions);
+ Assert.Equal(permissionCodes.OrderBy(p => p),
+ rolePermissions.Where(rp => rp.IsAssigned).Select(rp => rp.Code).OrderBy(p => p));
//验证关联用户的权限
- var getUserResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserById/{testUserId}");
- getUserResponse.EnsureSuccessStatusCode();
- var userData = await getUserResponse.Content.ReadFromNewtonsoftJsonAsync>();
- Assert.NotNull(userData);
- Assert.Equal(permissionCodes.OrderBy(p => p), userData.Data.Permissions.Select(p => p.PermissionCode).OrderBy(p => p));
+ var getAdminUserPermissionResponse =
+ await _client.GetAsync($"/api/AdminUser/GetAdminUserPermissions/{testUserId}");
+ var adminUserPermissions =
+ (await getAdminUserPermissionResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(adminUserPermissions);
+ Assert.Equal(permissionCodes.OrderBy(p => p),
+ adminUserPermissions.Where(aup => aup.IsAssigned).Select(p => p.Code).OrderBy(p => p));
+ }
+
+ ///
+ /// 设置用户权限测试
+ ///
+ ///
+ [Fact]
+ public async Task SetAdminUserSpecificPermissions_Test()
+ {
+ List rolePermissionCodes = [PermissionDefinitions.RoleCreate, PermissionDefinitions.RoleDelete];
+ var testRoleId = await CreateTestRoleAsync("TestSetAdminUserSpecificPermissionsRole", "", rolePermissionCodes);
+ var testUserId = await CreateTestAdminUser("TestSetAdminUserSpecificPermissionsUser", [testRoleId]);
+
+ var userPermissionsResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserPermissions/{testUserId}");
+ userPermissionsResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
+
+ var userPermissions = (await userPermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(userPermissions);
+ Assert.True(userPermissions.Where(p => p.IsAssigned)
+ .All(p => rolePermissionCodes.Contains(p.Code) && p.IsFromRole));
+
+ const string specificPermission = PermissionDefinitions.AdminUserSetPermissions;
+ var updateResponse =
+ await _client.PutAsJsonAsync>($"/api/AdminUser/SetAdminUserSpecificPermissions/{testUserId}",
+ [specificPermission]);
+ updateResponse.EnsureSuccessStatusCode();
+
+ userPermissionsResponse = await _client.GetAsync($"/api/AdminUser/GetAdminUserPermissions/{testUserId}");
+ userPermissionsResponse.EnsureSuccessStatusCode(); // 确保返回 200 OK
+ userPermissions = (await userPermissionsResponse.Content
+ .ReadFromNewtonsoftJsonAsync>>())?.Data;
+ Assert.NotNull(userPermissions);
+ var assignedPermissions = userPermissions.Where(p => p.IsAssigned).ToList();
+ Assert.True(assignedPermissions.Count == 3);
+ Assert.False(assignedPermissions.Single(p => p.Code == specificPermission).IsFromRole);
}
}
\ No newline at end of file
diff --git a/test/NetCorePal.D3Shop.Web.Tests/MyWebApplicationFactory.cs b/test/NetCorePal.D3Shop.Web.Tests/MyWebApplicationFactory.cs
index 004b8f6..9f7aafa 100644
--- a/test/NetCorePal.D3Shop.Web.Tests/MyWebApplicationFactory.cs
+++ b/test/NetCorePal.D3Shop.Web.Tests/MyWebApplicationFactory.cs
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.Hosting;
-using NetCorePal.Extensions.AspNetCore.Json;
namespace NetCorePal.D3Shop.Web.Tests
{
diff --git a/test/NetCorePal.D3Shop.Web.Tests/NetCorePal.D3Shop.Web.Tests.csproj b/test/NetCorePal.D3Shop.Web.Tests/NetCorePal.D3Shop.Web.Tests.csproj
index 151c9a7..d880f63 100644
--- a/test/NetCorePal.D3Shop.Web.Tests/NetCorePal.D3Shop.Web.Tests.csproj
+++ b/test/NetCorePal.D3Shop.Web.Tests/NetCorePal.D3Shop.Web.Tests.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/test/NetCorePal.D3Shop.Web.Tests/ProgramTests.cs b/test/NetCorePal.D3Shop.Web.Tests/ProgramTests.cs
index 883cb42..8735beb 100644
--- a/test/NetCorePal.D3Shop.Web.Tests/ProgramTests.cs
+++ b/test/NetCorePal.D3Shop.Web.Tests/ProgramTests.cs
@@ -1,8 +1,3 @@
-using System.Net.Http.Json;
-using Microsoft.AspNetCore.Mvc.Testing;
-using NetCorePal.Extensions.AspNetCore.Json;
-using Xunit;
-
namespace NetCorePal.D3Shop.Web.Tests
{
[Collection("web")]