修改User模块
This commit is contained in:
1 parent
d6471f97d3
commit
bb7162aaf6
21 files changed
+278
-336
No files matched your search
@@ -1,99 +1,57 @@
|
||||
# 用户模块迁移与运行
|
||||
# 用户模块
|
||||
|
||||
本模块参考 `D:/Works/KJD_WebService/KJD_WebService/BLL/WXXD/WXUserManage.cs` 重写,保留旧表映射,采用 ASP.NET Core 控制器、DTO、服务、FreeSql 仓储和现有 JWT 身份体系。所有新代码均含中文用途或关键规则注释。
|
||||
参考旧版 `D:/Works/KJD_WebService/KJD_WebService/BLL/WXXD/WXUserManage.cs`,沿用用户、积分、余额、充值备注等旧表。接口采用 JSON DTO 和现有 JWT 身份,不接受旧版拼接参数或客户端提供的操作者身份。
|
||||
|
||||
## 文件与职责
|
||||
|
||||
- 文件:`Controllers/UserController.cs`:`/user/[action]` 接口,统一要求 Bearer Token。
|
||||
- 文件:`Services/UserManagementService.cs`:主子账号管理、权限检查、分页、密码修改和流水查询。
|
||||
- 文件:`Services/UserManagementService.TopUp.cs`:充值备注与代理二维码。
|
||||
- 文件:`Services/UserFundsService.cs`:积分充值、积分转移、余额充值/消费;事务、行锁、请求去重与流水写入。
|
||||
- 文件:`Services/UserQueryService.cs`、`Repositories/UserRepository.cs`:认证和查询、主子账号有效配置继承。
|
||||
- 文件:`Services/UserPassword.cs`:带盐哈希密码与旧明文密码兼容。
|
||||
- 文件:`../Store.Users.Contracts/Dtos/UserManagementRequests.cs`、`UserFundsRequest.cs`、`UserTopUpRequests.cs`:输入验证与响应契约。
|
||||
- 文件:`Database/prepare-user-module.sql`:上线前密码列、唯一用户名、事务引擎及请求号列检查。
|
||||
- 文件:`../../Store.API/Controllers/AuthController.cs`:登录签发 JWT 前调用真实密码验证,不再接受任意密码。
|
||||
- 文件:`../../Tests/UserManagementSmoke/Program.cs`:临时 SQLite 集成验证,避免访问业务数据库。
|
||||
- 文件:`../Store.Users.Contracts/Dtos/*.cs`、`Dtos/ShopRenewRequest.cs`:非空、长度、数值范围、日期顺序、金额精度和二维码格式。`null` 更新字段保留原值,空字符串可清空可选文本。
|
||||
- 文件:`Services/UserAccessPolicy.cs`:集中定义管理员、主账号、子账号的操作范围。
|
||||
- 文件:`Services/UserManagementService.cs`:账户增删改查、密码和流水查询。
|
||||
- 文件:`Services/UserManagementService.TopUp.cs`:充值备注和公共代理二维码。
|
||||
- 文件:`Services/UserFundsService.cs`:资金事务、按主键顺序锁定账户、权限校验、请求去重和流水写入。
|
||||
- 文件:`Commands/ShopRenewCommand.cs`、`Behaviors/*.cs`:续费输入验证 → 事务 → 当前身份、账户归属及积分检查 → 店铺归属 → 扣费及延长有效期。
|
||||
- 文件:`Repositories/UserRepository.cs`:子账号的有效 OEM、费用和积分用户权限继承。
|
||||
- 文件:`Services/UserPassword.cs`:兼容旧明文密码;新建和修改密码保存带盐哈希。
|
||||
|
||||
## 接口
|
||||
## 权限规则
|
||||
|
||||
HTTP 方法约定:控制器通过 [DefaultHttpPost] 启用默认 POST。所有操作只接受 POST,无需逐个标记 [HttpPost]。该约定同时生成路由约束和端点元数据,接口文档也显示 POST。
|
||||
身份从登录上下文和数据库读取,管理员为 `SaLevel == UserAdminLevel.SuperAdmin`;普通主账号必须 `GroupId == UserGroup.MainAccount` 且无父账号。父账号缺失的子账号不会自动获得主账号权限。
|
||||
|
||||
| 方法 | 路径 | 访问与行为 |
|
||||
| --- | --- | --- |
|
||||
| POST | /user/GetUser?userName=... | 本人、直属主账号或管理员;省略用户名读取本人 |
|
||||
| POST | /user/GetAllUser | 管理员查询全部;普通主账号查询本人及直属子账号 |
|
||||
| POST | /user/GetSubUser | 管理员查询所有子账号,可用 ParentUserName 按父账号筛选;普通主账号仅能查询自己的子账号 |
|
||||
| POST | /user/AddUser | 管理员新增主账号 |
|
||||
| POST | /user/AddSubUser | 当前主账号新增直属子账号 |
|
||||
| POST | /user/UpdateUser | 管理员修改任意账户;普通主账号修改本人及直属子账号 |
|
||||
| POST | /user/UpdateSubUser | 管理员修改任意子账号;普通主账号修改直属子账号 |
|
||||
| POST | /user/DelUser?id=... | 管理员或直属主账号删除空账户 |
|
||||
| POST | /user/ChangePassword | 本人改密校验原密码;管理员/主账号可重置授权账户密码 |
|
||||
| POST | /user/GetUserPoints | 授权账户积分流水,支持起止时间、操作类型、店铺过滤 |
|
||||
| POST | /user/GetUserBalance | 授权账户余额流水,支持起止时间、支付类型、订单过滤 |
|
||||
| POST | /user/UpdateUserPoints | 管理员充值;本人向管理范围内账户转移自己的积分 |
|
||||
| POST | /user/UpdateUserBalance | 管理员充值或消费调整 |
|
||||
| POST | /user/AddUserTopUpMsg | 本人或授权账户提交充值备注 |
|
||||
| POST | /user/UpdateUserTopUpMsg | 管理员或主账号处理授权账户的备注,不自动充值 |
|
||||
| POST | /user/GetUserTopUpMsg | 管理员查看全部;主账号查看本人及直属子账号备注 |
|
||||
| POST | /user/UpdateTopUpQrcode | 管理员维护代理二维码 |
|
||||
| POST | /user/GetTopUpQrcode?agentCode=... | 登录用户读取代理二维码 |
|
||||
| POST | /user/ShopRenew | 保留原有 MediatR 事务续费用例 |
|
||||
| 操作 | 管理员 | 普通主账号 | 普通子账号 |
|
||||
| --- | --- | --- | --- |
|
||||
| 查询账户、资金流水 | 任意账户 | 本人和直属非管理员子账号 | 本人 |
|
||||
| 创建主账号 | 允许 | 不允许 | 不允许 |
|
||||
| 创建子账号 | 指定任意主账号 | 仅挂在本人名下 | 不允许 |
|
||||
| 修改资料、删除账户 | 任意账户 | 本人和直属非管理员子账号 | 不允许 |
|
||||
| 重置密码 | 任意账户,包括本人,无需原密码 | 子账号免原密码,本人需原密码 | 本人需原密码 |
|
||||
| 积分充值、余额调整 | 任意账户 | 不允许 | 不允许 |
|
||||
| 积分转移 | 向其他任意账户转出本人的积分 | 向直属非管理员子账号转出本人的积分 | 不允许 |
|
||||
| 店铺续费、提交充值备注 | 任意账户 | 本人和直属非管理员子账号 | 本人 |
|
||||
| 处理充值备注 | 任意账户 | 本人和直属非管理员子账号 | 不允许 |
|
||||
| 管理员级别、计费配置、公共充值二维码 | 允许 | 不允许 | 不允许 |
|
||||
|
||||
分页查询与流水查询通过 JSON 请求体提交;流水查询的 userName 与筛选字段放在同一对象中。UpdateUser、UpdateSubUser 使用 JSON 请求体,例如 `{"id":123,"nickName":"新昵称"}`。仅有单个业务参数的 GetUser、DelUser、GetTopUpQrcode 仍使用查询参数。
|
||||
管理员不受账户归属限制,仍须满足账户存在、余额充足等业务条件。删除要求无余额、无积分、无子账号、无店铺关联;本人满足条件也可删除,成功后注销会话。普通主账号不能向子账号授予自己没有的权限,不能通过管理具有管理员身份的子账号取得管理员权限。
|
||||
|
||||
分页 Page 从 1 开始,PageSize 默认 50,最大 200。流水时间参数为 StartTime、EndTime(包含边界)。资料更新 null 表示保留原值,空字符串清空文本字段。账户名不可修改,以免破坏历史关联。SaLevel 仅管理员可设置为 0/1,子账号不能成为管理员。普通主账号不能授予自己没有的权限,也不能修改计费配置。子账号积分用户权限、OEM 和每单费用继承主账号,保留 2.2/2.5 元费用下限。
|
||||
## 校验与业务边界
|
||||
|
||||
资金请求示例:
|
||||
DTO 用 `[Required]` 声明非空,使用数据注解和 `IValidatableObject` 声明输入规则。Service 入口统一调用 `RequestValidator.Validate`,续费通过 `ValidationBehavior` 调用 DTO 校验,保证内部调用也执行输入检查。Service 和后续管道只保留数据库状态、主子关系、权限、资金与店铺归属判断,不再重复校验必填字段。
|
||||
|
||||
```json
|
||||
{"userName":"target","requestId":"客户端生成的唯一请求号","amount":100,"operation":"充值","remark":"人工充值已核实"}
|
||||
账户登录名保持稳定,避免破坏店铺和历史流水关联。新建账户的主/子身份由接口决定,`GroupId` 必须与该身份一致。管理员创建子账号可指定 `ParentUserName`,普通主账号只能指定本人。查询列表先限定可见范围,再应用筛选与分页;不能用筛选条件扩大权限。
|
||||
|
||||
续费命令只接收 `ShopRenewRequest`,不再接收 `OperatorName`。管道从 `ICurrentUser` 读取实际操作者,目标账户省略时默认为本人。店铺必须属于目标账户,扣除目标账户积分,流水记录真实操作者。续费保留旧规则:每月最少 30 积分,在当前有效期和当前时间中较晚者的基础上延长。
|
||||
|
||||
资金请求的 `Amount` 为正数且最多两位小数;积分支持“充值”“转移”,余额支持“充值”“消费”。积分转入仍计入累计充值。资金和流水在同一事务提交;同一目标和资金类型下,重复 `RequestId` 拒绝再次记账。重试必须复用请求号。充值备注的处理不自动增加余额或积分。
|
||||
|
||||
## 接口与运行
|
||||
|
||||
所有用户接口要求 Bearer Token,采用 POST,路由为 `v{version}/user/[action]`。资料和资金操作使用 JSON 请求体;`GetUser`、`DelUser`、`GetTopUpQrcode` 使用查询参数。分页从 1 开始,默认每页 50 条,最大 200 条。
|
||||
|
||||
```powershell
|
||||
dotnet build Modules/Store.Users/Store.Users.csproj
|
||||
dotnet build Store.API/Store.Api.csproj
|
||||
dotnet run --project Store.API/Store.Api.csproj
|
||||
```
|
||||
|
||||
积分 Operation 支持“充值”“转移”;余额支持“充值”“消费”。Amount 始终为正数,最多两位小数。转移仅从当前登录账户转出,不支持负金额拉取对方积分。相同目标账户和资金类型下,重复 RequestId 返回已处理错误,不再次记账;调用失败重试必须保留请求号。不同请求号视作不同业务,调用方需确保业务唯一性。积分转入累计充值口径沿用旧系统。余额流水类型沿用旧系统充值 1、人工消费 0;商铺续费继续走专用接口。
|
||||
连接现有 MySQL 前确认账户表用户名唯一、密码列可容纳 Identity 哈希、资金相关表支持事务。应用不自动创建或修改旧表。旧系统直接比较明文密码的登录接口不能识别新哈希,需随调用方迁移。
|
||||
|
||||
## 运行与部署
|
||||
|
||||
1. 检查现有 MySQL `DefaultConnection` 配置和已有表。确认 `wxxd.user` 中存在可登录的 `sa_level=1` 管理员。
|
||||
2. 审阅并执行 `Database/prepare-user-module.sql`。应用不自动建表或改表;资金表必须是 InnoDB,用户名必须有唯一索引。
|
||||
3. 构建:`dotnet build Store.API/Store.Api.csproj`。
|
||||
4. 验证:`dotnet run --project Tests/UserManagementSmoke/UserManagementSmoke.csproj`,以及原有 `dotnet run --project Tests/ShopRenewSmoke/ShopRenewSmoke.csproj`。
|
||||
5. 启动:`dotnet run --project Store.API/Store.Api.csproj`。先调用宿主 `/api/v1.0/Auth/Login`,再携带 Bearer Token 调用用户接口。
|
||||
|
||||
认证兼容 WXUserManage 的旧明文密码和 Identity 带盐哈希,登录时仅验证,不修改密码;新建和修改密码直接保存哈希。旧项目按 SQL 明文比较密码的登录接口无法识别哈希密码,共用数据库时需同步切换相关调用方。新接口采用结构化 JSON,不兼容旧 inputData 拼接字符串及 time/code 签名。UserInfo 保留 Password 属性用于源码兼容,但不映射值、不向 JSON 序列化。
|
||||
|
||||
## 迁移边界与验证限制
|
||||
|
||||
旧文件中的 E57 第三方令牌、微信销售助手 Cookie、淘宝买手管理属于外部系统或独立业务,未加入用户账户模块。本次未修改旧项目或调用第三方服务。
|
||||
|
||||
集成验证使用临时 SQLite 库,覆盖认证、登录不修改密码、主子账号、越权、计费、资金写入、重复请求、超扣、强制流水失败的事务回滚、删除边界、备注和二维码更新。MySQL 的真实并发、行锁、历史表结构和旧客户端迁移仍需在测试库联调。可使用“代码审查”继续检查实现质量。
|
||||
|
||||
## 输入校验约定
|
||||
|
||||
User 模块的请求 DTO 只保留 `[Required]`,校验必填、null、空字符串和纯空白字符串。服务使用 `MAX.Framework.Validation.RequestValidator.Validate(request)` 统一执行这类非空校验,防止内部调用绕过 HTTP 模型验证。
|
||||
|
||||
```csharp
|
||||
using MAX.Framework.Validation;
|
||||
|
||||
RequestValidator.Validate(request);
|
||||
// 非空之外的规则由服务继续手动判断。
|
||||
```
|
||||
|
||||
长度、数值范围、金额精度、操作类型、字段组合、日期顺序和二维码 Base64 格式在服务层手动检查。可复用检查集中于 `Services/UserInputChecks.cs`,资金金额与操作类型直接由 UserFundsService 判断;续费的非空输入由 ShopRenewRequest 声明,其余规则通过命令验证管道调用服务层检查后执行事务。
|
||||
|
||||
权限、账户归属、数据库记录是否存在、余额是否足够、重复请求等业务规则继续在服务或业务管道中判断。不合法的参数抛出 ValidationException,权限和业务错误沿用现有业务异常;现有过滤器将它们转换为 HTTP 200 和对应业务码。
|
||||
|
||||
公共 RequestValidator 位于 `Core/MAX.Framework/Validation/RequestValidator.cs`。它仍支持标准 DataAnnotations 及 IValidatableObject,其他模块可以直接复用;User 模块“DTO 仅非空”的约定不改变公共校验器能力。该工具不递归验证嵌套对象。
|
||||
|
||||
## 账户管理权限
|
||||
|
||||
统一使用 Services/UserAccessPolicy:管理员可管理任意账户,普通主账号可管理本人及直属子账号;普通子账号保留本人查询和本人改密能力,不能管理其他账户。UpdateUser 支持此统一范围,UpdateSubUser 同时要求目标确实是子账号。管理员创建子账号时可传 ParentUserName 指定任意主账号;普通主账号只能指定自己。
|
||||
|
||||
ChangePassword 可传 UserName 指定目标,省略表示本人。本人改密仍须正确 OldPassword;管理员或主账号重置管理范围内的其他账户时仅需 NewPassword。成功后注销目标账户的会话。
|
||||
|
||||
已确认的财务权限保持:直接充值积分/余额、余额扣款、计费配置和公共代理二维码维护仅管理员可用;普通主账号不能提升管理员级别。积分转移仅从当前登录账户转出,普通主账号的转入目标限直属子账号。充值备注的提交/处理不代表资金到账。
|
||||
|
||||
ShopRenew 可传 UserName 指定授权账户,以店铺所属账户积分扣款,流水记录实际 OperatorName。账户删除仍禁止删除当前登录账户,且要求无积分、无余额、无子账号和无店铺关联。
|
||||
|
||||
管理员角色账户即使存在父账号关系,也不能由普通主账号修改或重置密码,避免通过子账号关系获得管理员身份。
|
||||
本次不修改或运行 Test 项目。编译和独立参数/权限边界验证不能替代真实 MySQL 的并发与表结构联调。旧文件中的 E57 令牌、销售助手 Cookie、淘宝买手不属于本模块范围。可以继续使用“代码审查”检查实现质量。
|
||||
Reference in new issue
Block a user