docs: 完善身份模块文档注释与字段说明
This commit is contained in:
@@ -41,38 +41,3 @@
|
|||||||
- src/Application/TakeoutSaaS.Application/Dictionary/Models/DictionaryItemDto.cs:12
|
- src/Application/TakeoutSaaS.Application/Dictionary/Models/DictionaryItemDto.cs:12
|
||||||
- src/Application/TakeoutSaaS.Application/Dictionary/Services/DictionaryAppService.cs:23
|
- src/Application/TakeoutSaaS.Application/Dictionary/Services/DictionaryAppService.cs:23
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Abstractions/IWeChatAuthService.cs:16
|
- src/Application/TakeoutSaaS.Application/Identity/Abstractions/IWeChatAuthService.cs:16
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/AssignUserRolesCommand.cs:10
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/BindRolePermissionsCommand.cs:10
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/CreateMenuCommand.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/CreatePermissionCommand.cs:11
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/CreateRoleCommand.cs:16
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/DeleteMenuCommand.cs:10
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/DeletePermissionCommand.cs:10
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/DeleteRoleCommand.cs:10
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/UpdateMenuCommand.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/UpdatePermissionCommand.cs:11
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Commands/UpdateRoleCommand.cs:11
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Contracts/AdminLoginRequest.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Contracts/RefreshTokenRequest.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Contracts/WeChatLoginRequest.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/AssignUserRolesCommandHandler.cs:16
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/BindRolePermissionsCommandHandler.cs:16
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/CreatePermissionCommandHandler.cs:18
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/CreateRoleCommandHandler.cs:20
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/DeletePermissionCommandHandler.cs:16
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/DeleteRoleCommandHandler.cs:16
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/DeleteRoleTemplateCommandHandler.cs:13
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/MenuMapper.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/PermissionTreeQueryHandler.cs:17
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/SearchPermissionsQueryHandler.cs:18
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/SearchRolesQueryHandler.cs:18
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/UpdatePermissionCommandHandler.cs:17
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Handlers/UpdateRoleCommandHandler.cs:17
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Queries/SearchPermissionsQuery.cs:12
|
|
||||||
- src/Application/TakeoutSaaS.Application/Identity/Queries/SearchRolesQuery.cs:17
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Filters/ApiResponseResultFilter.cs:15
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Filters/ValidateModelAttribute.cs:13
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Middleware/CorrelationIdMiddleware.cs:18
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Middleware/ExceptionHandlingMiddleware.cs:34
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Middleware/RequestLoggingMiddleware.cs:13
|
|
||||||
- src/Core/TakeoutSaaS.Shared.Web/Middleware/SecurityHeadersMiddleware.cs:10
|
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record AssignUserRolesCommand : IRequest<bool>
|
public sealed record AssignUserRolesCommand : IRequest<bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用户 ID。
|
||||||
|
/// </summary>
|
||||||
public long UserId { get; init; }
|
public long UserId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID 集合。
|
||||||
|
/// </summary>
|
||||||
public long[] RoleIds { get; init; } = Array.Empty<long>();
|
public long[] RoleIds { get; init; } = Array.Empty<long>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,18 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record BindRolePermissionsCommand : IRequest<bool>
|
public sealed record BindRolePermissionsCommand : IRequest<bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID。
|
||||||
|
/// </summary>
|
||||||
public long RoleId { get; init; }
|
public long RoleId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 租户 ID(可选,空则取当前上下文)。
|
||||||
|
/// </summary>
|
||||||
public long? TenantId { get; init; }
|
public long? TenantId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限 ID 集合。
|
||||||
|
/// </summary>
|
||||||
public long[] PermissionIds { get; init; } = Array.Empty<long>();
|
public long[] PermissionIds { get; init; } = Array.Empty<long>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,18 +9,73 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record CreateMenuCommand : IRequest<MenuDefinitionDto>
|
public sealed record CreateMenuCommand : IRequest<MenuDefinitionDto>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 父级菜单 ID。
|
||||||
|
/// </summary>
|
||||||
public long ParentId { get; init; }
|
public long ParentId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 菜单名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 路由路径。
|
||||||
|
/// </summary>
|
||||||
public string Path { get; init; } = string.Empty;
|
public string Path { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 前端组件路径。
|
||||||
|
/// </summary>
|
||||||
public string Component { get; init; } = string.Empty;
|
public string Component { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 显示标题。
|
||||||
|
/// </summary>
|
||||||
public string Title { get; init; } = string.Empty;
|
public string Title { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标。
|
||||||
|
/// </summary>
|
||||||
public string? Icon { get; init; }
|
public string? Icon { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否外链。
|
||||||
|
/// </summary>
|
||||||
public bool IsIframe { get; init; }
|
public bool IsIframe { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 外链地址。
|
||||||
|
/// </summary>
|
||||||
public string? Link { get; init; }
|
public string? Link { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否缓存。
|
||||||
|
/// </summary>
|
||||||
public bool KeepAlive { get; init; }
|
public bool KeepAlive { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序序号。
|
||||||
|
/// </summary>
|
||||||
public int SortOrder { get; init; }
|
public int SortOrder { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 访问所需权限。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> RequiredPermissions { get; init; } = [];
|
public IReadOnlyCollection<string> RequiredPermissions { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元信息权限。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> MetaPermissions { get; init; } = [];
|
public IReadOnlyCollection<string> MetaPermissions { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元信息角色。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> MetaRoles { get; init; } = [];
|
public IReadOnlyCollection<string> MetaRoles { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按钮权限集合。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<MenuAuthItemDto> AuthList { get; init; } = [];
|
public IReadOnlyCollection<MenuAuthItemDto> AuthList { get; init; } = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,33 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record CreatePermissionCommand : IRequest<PermissionDto>
|
public sealed record CreatePermissionCommand : IRequest<PermissionDto>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 父级权限 ID。
|
||||||
|
/// </summary>
|
||||||
public long ParentId { get; init; } = 0;
|
public long ParentId { get; init; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序序号。
|
||||||
|
/// </summary>
|
||||||
public int SortOrder { get; init; } = 0;
|
public int SortOrder { get; init; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限类型(group/leaf)。
|
||||||
|
/// </summary>
|
||||||
public string Type { get; init; } = "leaf";
|
public string Type { get; init; } = "leaf";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限编码。
|
||||||
|
/// </summary>
|
||||||
public string Code { get; init; } = string.Empty;
|
public string Code { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述。
|
||||||
|
/// </summary>
|
||||||
public string? Description { get; init; }
|
public string? Description { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,18 @@ public sealed record CreateRoleCommand : IRequest<RoleDto>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long? TenantId { get; init; }
|
public long? TenantId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色编码。
|
||||||
|
/// </summary>
|
||||||
public string Code { get; init; } = string.Empty;
|
public string Code { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述。
|
||||||
|
/// </summary>
|
||||||
public string? Description { get; init; }
|
public string? Description { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,8 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record DeleteMenuCommand : IRequest<bool>
|
public sealed record DeleteMenuCommand : IRequest<bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 菜单 ID。
|
||||||
|
/// </summary>
|
||||||
public long Id { get; init; }
|
public long Id { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,8 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record DeletePermissionCommand : IRequest<bool>
|
public sealed record DeletePermissionCommand : IRequest<bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 权限 ID。
|
||||||
|
/// </summary>
|
||||||
public long PermissionId { get; init; }
|
public long PermissionId { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record DeleteRoleCommand : IRequest<bool>
|
public sealed record DeleteRoleCommand : IRequest<bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID。
|
||||||
|
/// </summary>
|
||||||
public long RoleId { get; init; }
|
public long RoleId { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,19 +9,78 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record UpdateMenuCommand : IRequest<MenuDefinitionDto?>
|
public sealed record UpdateMenuCommand : IRequest<MenuDefinitionDto?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 菜单 ID。
|
||||||
|
/// </summary>
|
||||||
public long Id { get; init; }
|
public long Id { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 父级菜单 ID。
|
||||||
|
/// </summary>
|
||||||
public long ParentId { get; init; }
|
public long ParentId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 菜单名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 路由路径。
|
||||||
|
/// </summary>
|
||||||
public string Path { get; init; } = string.Empty;
|
public string Path { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 前端组件路径。
|
||||||
|
/// </summary>
|
||||||
public string Component { get; init; } = string.Empty;
|
public string Component { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 显示标题。
|
||||||
|
/// </summary>
|
||||||
public string Title { get; init; } = string.Empty;
|
public string Title { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标。
|
||||||
|
/// </summary>
|
||||||
public string? Icon { get; init; }
|
public string? Icon { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否外链。
|
||||||
|
/// </summary>
|
||||||
public bool IsIframe { get; init; }
|
public bool IsIframe { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 外链地址。
|
||||||
|
/// </summary>
|
||||||
public string? Link { get; init; }
|
public string? Link { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否缓存。
|
||||||
|
/// </summary>
|
||||||
public bool KeepAlive { get; init; }
|
public bool KeepAlive { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序序号。
|
||||||
|
/// </summary>
|
||||||
public int SortOrder { get; init; }
|
public int SortOrder { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 访问所需权限。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> RequiredPermissions { get; init; } = [];
|
public IReadOnlyCollection<string> RequiredPermissions { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元信息权限。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> MetaPermissions { get; init; } = [];
|
public IReadOnlyCollection<string> MetaPermissions { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元信息角色。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<string> MetaRoles { get; init; } = [];
|
public IReadOnlyCollection<string> MetaRoles { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按钮权限集合。
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyCollection<MenuAuthItemDto> AuthList { get; init; } = [];
|
public IReadOnlyCollection<MenuAuthItemDto> AuthList { get; init; } = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,33 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record UpdatePermissionCommand : IRequest<PermissionDto?>
|
public sealed record UpdatePermissionCommand : IRequest<PermissionDto?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 权限 ID。
|
||||||
|
/// </summary>
|
||||||
public long PermissionId { get; init; }
|
public long PermissionId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 父级权限 ID。
|
||||||
|
/// </summary>
|
||||||
public long ParentId { get; init; }
|
public long ParentId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序序号。
|
||||||
|
/// </summary>
|
||||||
public int SortOrder { get; init; }
|
public int SortOrder { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限类型(group/leaf)。
|
||||||
|
/// </summary>
|
||||||
public string Type { get; init; } = "leaf";
|
public string Type { get; init; } = "leaf";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述。
|
||||||
|
/// </summary>
|
||||||
public string? Description { get; init; }
|
public string? Description { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ namespace TakeoutSaaS.Application.Identity.Commands;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record UpdateRoleCommand : IRequest<RoleDto?>
|
public sealed record UpdateRoleCommand : IRequest<RoleDto?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID。
|
||||||
|
/// </summary>
|
||||||
public long RoleId { get; init; }
|
public long RoleId { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -15,6 +18,13 @@ public sealed record UpdateRoleCommand : IRequest<RoleDto?>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long? TenantId { get; init; }
|
public long? TenantId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; init; } = string.Empty;
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色描述。
|
||||||
|
/// </summary>
|
||||||
public string? Description { get; init; }
|
public string? Description { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,16 @@ namespace TakeoutSaaS.Application.Identity.Contracts;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class AdminLoginRequest
|
public sealed class AdminLoginRequest
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 账号。
|
||||||
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string Account { get; set; } = string.Empty;
|
public string Account { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 密码。
|
||||||
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(128)]
|
[MaxLength(128)]
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace TakeoutSaaS.Application.Identity.Contracts;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class RefreshTokenRequest
|
public sealed class RefreshTokenRequest
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新令牌。
|
||||||
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
public string RefreshToken { get; set; } = string.Empty;
|
public string RefreshToken { get; set; } = string.Empty;
|
||||||
|
|||||||
@@ -7,17 +7,32 @@ namespace TakeoutSaaS.Application.Identity.Contracts;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class WeChatLoginRequest
|
public sealed class WeChatLoginRequest
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// wx.login 返回的临时 code。
|
||||||
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(128)]
|
[MaxLength(128)]
|
||||||
public string Code { get; set; } = string.Empty;
|
public string Code { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户昵称。
|
||||||
|
/// </summary>
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string? Nickname { get; set; }
|
public string? Nickname { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 头像地址。
|
||||||
|
/// </summary>
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
public string? Avatar { get; set; }
|
public string? Avatar { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加密用户数据。
|
||||||
|
/// </summary>
|
||||||
public string? EncryptedData { get; set; }
|
public string? EncryptedData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加密向量。
|
||||||
|
/// </summary>
|
||||||
public string? Iv { get; set; }
|
public string? Iv { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ public sealed class AssignUserRolesCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<AssignUserRolesCommand, bool>
|
: IRequestHandler<AssignUserRolesCommand, bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理用户角色分配请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">分配命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>执行结果。</returns>
|
||||||
public async Task<bool> Handle(AssignUserRolesCommand request, CancellationToken cancellationToken)
|
public async Task<bool> Handle(AssignUserRolesCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ public sealed class BindRolePermissionsCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<BindRolePermissionsCommand, bool>
|
: IRequestHandler<BindRolePermissionsCommand, bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理角色权限绑定请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">绑定命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>执行结果。</returns>
|
||||||
public async Task<bool> Handle(BindRolePermissionsCommand request, CancellationToken cancellationToken)
|
public async Task<bool> Handle(BindRolePermissionsCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ public sealed class CreatePermissionCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<CreatePermissionCommand, PermissionDto>
|
: IRequestHandler<CreatePermissionCommand, PermissionDto>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理创建权限请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">创建命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>创建后的权限 DTO。</returns>
|
||||||
public async Task<PermissionDto> Handle(CreatePermissionCommand request, CancellationToken cancellationToken)
|
public async Task<PermissionDto> Handle(CreatePermissionCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ public sealed class CreateRoleCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<CreateRoleCommand, RoleDto>
|
: IRequestHandler<CreateRoleCommand, RoleDto>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理创建角色请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">创建命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>创建后的角色 DTO。</returns>
|
||||||
public async Task<RoleDto> Handle(CreateRoleCommand request, CancellationToken cancellationToken)
|
public async Task<RoleDto> Handle(CreateRoleCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ public sealed class DeletePermissionCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<DeletePermissionCommand, bool>
|
: IRequestHandler<DeletePermissionCommand, bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理删除权限请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">删除命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>执行结果。</returns>
|
||||||
public async Task<bool> Handle(DeletePermissionCommand request, CancellationToken cancellationToken)
|
public async Task<bool> Handle(DeletePermissionCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ public sealed class DeleteRoleCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<DeleteRoleCommand, bool>
|
: IRequestHandler<DeleteRoleCommand, bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理删除角色请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">删除命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>执行结果。</returns>
|
||||||
public async Task<bool> Handle(DeleteRoleCommand request, CancellationToken cancellationToken)
|
public async Task<bool> Handle(DeleteRoleCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文
|
// 1. 获取租户上下文
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ namespace TakeoutSaaS.Application.Identity.Handlers;
|
|||||||
public sealed class DeleteRoleTemplateCommandHandler(IRoleTemplateRepository roleTemplateRepository)
|
public sealed class DeleteRoleTemplateCommandHandler(IRoleTemplateRepository roleTemplateRepository)
|
||||||
: IRequestHandler<DeleteRoleTemplateCommand, bool>
|
: IRequestHandler<DeleteRoleTemplateCommand, bool>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理删除角色模板请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">删除命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>执行结果。</returns>
|
||||||
public async Task<bool> Handle(DeleteRoleTemplateCommand request, CancellationToken cancellationToken)
|
public async Task<bool> Handle(DeleteRoleTemplateCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 查询模板
|
// 1. 查询模板
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ namespace TakeoutSaaS.Application.Identity.Handlers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class MenuMapper
|
internal static class MenuMapper
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 将菜单实体映射为 DTO。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">菜单实体。</param>
|
||||||
|
/// <returns>菜单定义 DTO。</returns>
|
||||||
public static MenuDefinitionDto ToDto(MenuDefinition entity)
|
public static MenuDefinitionDto ToDto(MenuDefinition entity)
|
||||||
{
|
{
|
||||||
// 1. 解析权限字段
|
// 1. 解析权限字段
|
||||||
@@ -42,6 +47,11 @@ internal static class MenuMapper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 DTO 字段填充到实体。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">菜单实体。</param>
|
||||||
|
/// <param name="dto">菜单 DTO。</param>
|
||||||
public static void FillEntity(MenuDefinition entity, MenuDefinitionDto dto)
|
public static void FillEntity(MenuDefinition entity, MenuDefinitionDto dto)
|
||||||
{
|
{
|
||||||
// 1. 赋值基础字段
|
// 1. 赋值基础字段
|
||||||
@@ -65,6 +75,14 @@ internal static class MenuMapper
|
|||||||
: JsonSerializer.Serialize(dto.AuthList);
|
: JsonSerializer.Serialize(dto.AuthList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建或更新菜单实体并返回 DTO。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="existing">已存在的菜单实体。</param>
|
||||||
|
/// <param name="tenantId">租户 ID。</param>
|
||||||
|
/// <param name="name">菜单名称。</param>
|
||||||
|
/// <param name="payload">菜单 DTO 载荷。</param>
|
||||||
|
/// <returns>菜单定义 DTO。</returns>
|
||||||
public static MenuDefinitionDto FromCommand(MenuDefinition? existing, long tenantId, string name, MenuDefinitionDto payload)
|
public static MenuDefinitionDto FromCommand(MenuDefinition? existing, long tenantId, string name, MenuDefinitionDto payload)
|
||||||
{
|
{
|
||||||
// 1. 构造实体
|
// 1. 构造实体
|
||||||
@@ -81,11 +99,21 @@ internal static class MenuMapper
|
|||||||
return ToDto(entity);
|
return ToDto(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将权限/角色集合合并为存储字符串。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codes">编码集合。</param>
|
||||||
|
/// <returns>逗号分隔字符串。</returns>
|
||||||
public static string JoinCodes(IEnumerable<string> codes)
|
public static string JoinCodes(IEnumerable<string> codes)
|
||||||
{
|
{
|
||||||
return string.Join(',', codes.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).Distinct(StringComparer.OrdinalIgnoreCase));
|
return string.Join(',', codes.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).Distinct(StringComparer.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将逗号分隔编码拆分为集合。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codes">编码字符串。</param>
|
||||||
|
/// <returns>编码数组。</returns>
|
||||||
public static string[] SplitCodes(string? codes)
|
public static string[] SplitCodes(string? codes)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(codes))
|
if (string.IsNullOrWhiteSpace(codes))
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ public sealed class PermissionTreeQueryHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<PermissionTreeQuery, IReadOnlyList<PermissionTreeDto>>
|
: IRequestHandler<PermissionTreeQuery, IReadOnlyList<PermissionTreeDto>>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构建权限树。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">查询参数。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>权限树列表。</returns>
|
||||||
public async Task<IReadOnlyList<PermissionTreeDto>> Handle(PermissionTreeQuery request, CancellationToken cancellationToken)
|
public async Task<IReadOnlyList<PermissionTreeDto>> Handle(PermissionTreeQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文并查询权限
|
// 1. 获取租户上下文并查询权限
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ public sealed class SearchPermissionsQueryHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<SearchPermissionsQuery, PagedResult<PermissionDto>>
|
: IRequestHandler<SearchPermissionsQuery, PagedResult<PermissionDto>>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行权限分页查询。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">查询参数。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>分页结果。</returns>
|
||||||
public async Task<PagedResult<PermissionDto>> Handle(SearchPermissionsQuery request, CancellationToken cancellationToken)
|
public async Task<PagedResult<PermissionDto>> Handle(SearchPermissionsQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文并查询权限
|
// 1. 获取租户上下文并查询权限
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ public sealed class SearchRolesQueryHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<SearchRolesQuery, PagedResult<RoleDto>>
|
: IRequestHandler<SearchRolesQuery, PagedResult<RoleDto>>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行角色分页查询。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">查询参数。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>分页结果。</returns>
|
||||||
public async Task<PagedResult<RoleDto>> Handle(SearchRolesQuery request, CancellationToken cancellationToken)
|
public async Task<PagedResult<RoleDto>> Handle(SearchRolesQuery request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文并查询角色
|
// 1. 获取租户上下文并查询角色
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ public sealed class UpdatePermissionCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<UpdatePermissionCommand, PermissionDto?>
|
: IRequestHandler<UpdatePermissionCommand, PermissionDto?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行权限更新。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">更新命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>更新后的权限 DTO 或 null。</returns>
|
||||||
public async Task<PermissionDto?> Handle(UpdatePermissionCommand request, CancellationToken cancellationToken)
|
public async Task<PermissionDto?> Handle(UpdatePermissionCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文并查询权限
|
// 1. 获取租户上下文并查询权限
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ public sealed class UpdateRoleCommandHandler(
|
|||||||
ITenantProvider tenantProvider)
|
ITenantProvider tenantProvider)
|
||||||
: IRequestHandler<UpdateRoleCommand, RoleDto?>
|
: IRequestHandler<UpdateRoleCommand, RoleDto?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行角色更新。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">更新命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>更新后的角色 DTO 或 null。</returns>
|
||||||
public async Task<RoleDto?> Handle(UpdateRoleCommand request, CancellationToken cancellationToken)
|
public async Task<RoleDto?> Handle(UpdateRoleCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 1. 获取租户上下文并查询角色
|
// 1. 获取租户上下文并查询角色
|
||||||
|
|||||||
@@ -9,9 +9,24 @@ namespace TakeoutSaaS.Application.Identity.Queries;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SearchPermissionsQuery : IRequest<PagedResult<PermissionDto>>
|
public sealed class SearchPermissionsQuery : IRequest<PagedResult<PermissionDto>>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索关键字。
|
||||||
|
/// </summary>
|
||||||
public string? Keyword { get; init; }
|
public string? Keyword { get; init; }
|
||||||
|
/// <summary>
|
||||||
|
/// 页码(从 1 开始)。
|
||||||
|
/// </summary>
|
||||||
public int Page { get; init; } = 1;
|
public int Page { get; init; } = 1;
|
||||||
|
/// <summary>
|
||||||
|
/// 每页条数。
|
||||||
|
/// </summary>
|
||||||
public int PageSize { get; init; } = 20;
|
public int PageSize { get; init; } = 20;
|
||||||
|
/// <summary>
|
||||||
|
/// 排序字段。
|
||||||
|
/// </summary>
|
||||||
public string? SortBy { get; init; }
|
public string? SortBy { get; init; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否降序。
|
||||||
|
/// </summary>
|
||||||
public bool SortDescending { get; init; } = true;
|
public bool SortDescending { get; init; } = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,24 @@ public sealed class SearchRolesQuery : IRequest<PagedResult<RoleDto>>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long? TenantId { get; init; }
|
public long? TenantId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索关键字。
|
||||||
|
/// </summary>
|
||||||
public string? Keyword { get; init; }
|
public string? Keyword { get; init; }
|
||||||
|
/// <summary>
|
||||||
|
/// 页码(从 1 开始)。
|
||||||
|
/// </summary>
|
||||||
public int Page { get; init; } = 1;
|
public int Page { get; init; } = 1;
|
||||||
|
/// <summary>
|
||||||
|
/// 每页条数。
|
||||||
|
/// </summary>
|
||||||
public int PageSize { get; init; } = 20;
|
public int PageSize { get; init; } = 20;
|
||||||
|
/// <summary>
|
||||||
|
/// 排序字段。
|
||||||
|
/// </summary>
|
||||||
public string? SortBy { get; init; }
|
public string? SortBy { get; init; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否降序。
|
||||||
|
/// </summary>
|
||||||
public bool SortDescending { get; init; } = true;
|
public bool SortDescending { get; init; } = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,20 +12,29 @@ namespace TakeoutSaaS.Shared.Web.Filters;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ApiResponseResultFilter : IAsyncResultFilter
|
public sealed class ApiResponseResultFilter : IAsyncResultFilter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行结果过滤,将 ApiResponse 映射为对应 HTTP 状态码。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">结果执行上下文。</param>
|
||||||
|
/// <param name="next">后续委托。</param>
|
||||||
|
/// <returns>异步任务。</returns>
|
||||||
public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
||||||
{
|
{
|
||||||
|
// 1. 仅处理 ObjectResult
|
||||||
// 只处理 ObjectResult 类型的结果
|
// 只处理 ObjectResult 类型的结果
|
||||||
if (context.Result is not ObjectResult objectResult)
|
if (context.Result is not ObjectResult objectResult)
|
||||||
{
|
{
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 结果为空直接跳过
|
||||||
var value = objectResult.Value;
|
var value = objectResult.Value;
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 确认类型为 ApiResponse<T>
|
||||||
// 检查是否是 ApiResponse<T> 类型
|
// 检查是否是 ApiResponse<T> 类型
|
||||||
var valueType = value.GetType();
|
var valueType = value.GetType();
|
||||||
if (!IsApiResponseType(valueType))
|
if (!IsApiResponseType(valueType))
|
||||||
@@ -33,6 +42,7 @@ public sealed class ApiResponseResultFilter : IAsyncResultFilter
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. 读取 Success 与 Code
|
||||||
// 使用反射获取 Success 和 Code 属性
|
// 使用反射获取 Success 和 Code 属性
|
||||||
// 注意:由于已通过 IsApiResponseType 检查,属性名是固定的
|
// 注意:由于已通过 IsApiResponseType 检查,属性名是固定的
|
||||||
const string successPropertyName = "Success";
|
const string successPropertyName = "Success";
|
||||||
@@ -48,9 +58,11 @@ public sealed class ApiResponseResultFilter : IAsyncResultFilter
|
|||||||
var success = (bool)(successProperty.GetValue(value) ?? false);
|
var success = (bool)(successProperty.GetValue(value) ?? false);
|
||||||
var code = (int)(codeProperty.GetValue(value) ?? 200);
|
var code = (int)(codeProperty.GetValue(value) ?? 200);
|
||||||
|
|
||||||
|
// 5. 映射 HTTP 状态码
|
||||||
// 根据 Success 和 Code 设置 HTTP 状态码
|
// 根据 Success 和 Code 设置 HTTP 状态码
|
||||||
var statusCode = success ? MapSuccessCode(code) : MapErrorCode(code);
|
var statusCode = success ? MapSuccessCode(code) : MapErrorCode(code);
|
||||||
|
|
||||||
|
// 6. 回写状态码
|
||||||
// 更新 ObjectResult 的状态码
|
// 更新 ObjectResult 的状态码
|
||||||
objectResult.StatusCode = statusCode;
|
objectResult.StatusCode = statusCode;
|
||||||
|
|
||||||
@@ -101,4 +113,3 @@ public sealed class ApiResponseResultFilter : IAsyncResultFilter
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ namespace TakeoutSaaS.Shared.Web.Filters;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ValidateModelAttribute : ActionFilterAttribute
|
public sealed class ValidateModelAttribute : ActionFilterAttribute
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 在 Action 执行前拦截模型验证错误。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">执行上下文。</param>
|
||||||
public override void OnActionExecuting(ActionExecutingContext context)
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
{
|
{
|
||||||
|
// 1. 模型验证未通过则返回 422
|
||||||
if (!context.ModelState.IsValid)
|
if (!context.ModelState.IsValid)
|
||||||
{
|
{
|
||||||
var errors = context.ModelState
|
var errors = context.ModelState
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<Correl
|
|||||||
private const string SpanHeader = "X-Span-Id";
|
private const string SpanHeader = "X-Span-Id";
|
||||||
private const string RequestHeader = "X-Request-Id";
|
private const string RequestHeader = "X-Request-Id";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管道入口,确保 TraceId/SpanId 贯穿请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP 上下文。</param>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
|
// 1. 确保活动存在并启动
|
||||||
var ownsActivity = Activity.Current is null;
|
var ownsActivity = Activity.Current is null;
|
||||||
var activity = Activity.Current ?? new Activity("TakeoutSaaS.Request");
|
var activity = Activity.Current ?? new Activity("TakeoutSaaS.Request");
|
||||||
|
|
||||||
@@ -26,6 +31,7 @@ public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<Correl
|
|||||||
activity.Start();
|
activity.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 生成/解析 TraceId、SpanId
|
||||||
var traceId = activity.TraceId.ToString();
|
var traceId = activity.TraceId.ToString();
|
||||||
var spanId = activity.SpanId.ToString();
|
var spanId = activity.SpanId.ToString();
|
||||||
|
|
||||||
@@ -34,6 +40,7 @@ public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<Correl
|
|||||||
traceId = ResolveTraceId(context);
|
traceId = ResolveTraceId(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 写入上下文与响应头
|
||||||
context.TraceIdentifier = traceId;
|
context.TraceIdentifier = traceId;
|
||||||
TraceContext.TraceId = traceId;
|
TraceContext.TraceId = traceId;
|
||||||
TraceContext.SpanId = spanId;
|
TraceContext.SpanId = spanId;
|
||||||
@@ -45,6 +52,7 @@ public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<Correl
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 4. 带 Scope 调用后续中间件
|
||||||
using (logger.BeginScope(new Dictionary<string, object>
|
using (logger.BeginScope(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
["TraceId"] = traceId,
|
["TraceId"] = traceId,
|
||||||
@@ -57,6 +65,7 @@ public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<Correl
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
// 5. 清理上下文与活动
|
||||||
TraceContext.Clear();
|
TraceContext.Clear();
|
||||||
if (ownsActivity)
|
if (ownsActivity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public sealed class ExceptionHandlingMiddleware(RequestDelegate next, ILogger<Ex
|
|||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 中间件入口,捕获并统一处理异常。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP 上下文。</param>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -39,17 +43,21 @@ public sealed class ExceptionHandlingMiddleware(RequestDelegate next, ILogger<Ex
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// 1. 记录异常
|
||||||
logger.LogError(ex, "未处理异常:{Message}", ex.Message);
|
logger.LogError(ex, "未处理异常:{Message}", ex.Message);
|
||||||
|
// 2. 返回统一错误响应
|
||||||
await HandleExceptionAsync(context, ex);
|
await HandleExceptionAsync(context, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task HandleExceptionAsync(HttpContext context, Exception exception)
|
private Task HandleExceptionAsync(HttpContext context, Exception exception)
|
||||||
{
|
{
|
||||||
|
// 1. 构建错误响应与状态码
|
||||||
var (statusCode, response) = BuildErrorResponse(exception);
|
var (statusCode, response) = BuildErrorResponse(exception);
|
||||||
|
|
||||||
if (environment.IsDevelopment())
|
if (environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
// 2. 开发环境附加细节
|
||||||
response = response with
|
response = response with
|
||||||
{
|
{
|
||||||
Message = exception.Message,
|
Message = exception.Message,
|
||||||
@@ -61,6 +69,7 @@ public sealed class ExceptionHandlingMiddleware(RequestDelegate next, ILogger<Ex
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 写入响应
|
||||||
context.Response.StatusCode = statusCode;
|
context.Response.StatusCode = statusCode;
|
||||||
context.Response.ContentType = "application/json";
|
context.Response.ContentType = "application/json";
|
||||||
return context.Response.WriteAsJsonAsync(response, SerializerOptions);
|
return context.Response.WriteAsJsonAsync(response, SerializerOptions);
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ namespace TakeoutSaaS.Shared.Web.Middleware;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
|
public sealed class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 记录请求日志并调用后续中间件。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP 上下文。</param>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
|
// 1. 启动计时
|
||||||
var stopwatch = Stopwatch.StartNew();
|
var stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -19,6 +24,7 @@ public sealed class RequestLoggingMiddleware(RequestDelegate next, ILogger<Reque
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
// 2. 结束计时并输出日志
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
var traceId = TraceContext.TraceId ?? context.TraceIdentifier;
|
var traceId = TraceContext.TraceId ?? context.TraceIdentifier;
|
||||||
var spanId = TraceContext.SpanId ?? Activity.Current?.SpanId.ToString() ?? string.Empty;
|
var spanId = TraceContext.SpanId ?? Activity.Current?.SpanId.ToString() ?? string.Empty;
|
||||||
|
|||||||
@@ -7,14 +7,19 @@ namespace TakeoutSaaS.Shared.Web.Middleware;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SecurityHeadersMiddleware(RequestDelegate next)
|
public sealed class SecurityHeadersMiddleware(RequestDelegate next)
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置基础安全响应头。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP 上下文。</param>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
|
// 1. 写入安全响应头
|
||||||
var headers = context.Response.Headers;
|
var headers = context.Response.Headers;
|
||||||
headers["X-Content-Type-Options"] = "nosniff";
|
headers["X-Content-Type-Options"] = "nosniff";
|
||||||
headers["X-Frame-Options"] = "DENY";
|
headers["X-Frame-Options"] = "DENY";
|
||||||
headers["X-XSS-Protection"] = "1; mode=block";
|
headers["X-XSS-Protection"] = "1; mode=block";
|
||||||
headers["Referrer-Policy"] = "no-referrer";
|
headers["Referrer-Policy"] = "no-referrer";
|
||||||
|
// 2. 继续后续管道
|
||||||
await next(context);
|
await next(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user