Files
StoreWeb/Modules/Store.Users/README.md
T
2026-10-29 16:34:25 +08:00

66 lines
6.3 KiB
Markdown

# 用户模块
参考旧版 `D:/Works/KJD_WebService/KJD_WebService/BLL/WXXD/WXUserManage.cs`,沿用用户、积分、余额、充值备注等旧表。接口采用 JSON DTO 和现有 Bearer Token 身份,不接受旧版拼接参数或客户端提供的操作者身份。
## 文件与职责
- 文件:`../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`:兼容旧明文密码;新建和修改密码保存带盐哈希。
## 查询入口与后续缓存接入
公共用户查询已经通过 `IUserQueryService → UserQueryService → IUserRepository.GetUser` 集中读取,本次保留现有实现。登录凭据检查、资金操作和事务内的账户读取仍直接访问数据库,不为缓存准备迁移事务写入。
`GetUser` 返回主子账号配置合并后的结果,并被 Shops 等模块用于权限判断,不能直接给整个结果加缓存。后续只缓存允许延迟的资料时,应将展示查询与实时授权读取明确分开;若缓存继承配置,还需在主账号变更时失效关联子账号数据。密码、权限、余额与积分不得因接入展示缓存而改用旧状态。
店铺续费写入位于 Users,其到期记录由 Shops 的 Repository 直接查询数据库。当前不使用仓储缓存,不注册缓存提供程序或续费缓存失效管道;续费仍由原有事务管道统一提交或回滚。
## 权限规则
身份从登录上下文和数据库读取,管理员为 `SaLevel == UserAdminLevel.SuperAdmin`;普通主账号必须 `GroupId == UserGroup.MainAccount` 且无父账号。父账号缺失的子账号不会自动获得主账号权限。
| 操作 | 管理员 | 普通主账号 | 普通子账号 |
| --- | --- | --- | --- |
| 查询账户、资金流水 | 任意账户 | 本人和直属非管理员子账号 | 本人 |
| 创建主账号 | 允许 | 不允许 | 不允许 |
| 创建子账号 | 指定任意主账号 | 仅挂在本人名下 | 不允许 |
| 修改资料、删除账户 | 任意账户 | 本人和直属非管理员子账号 | 不允许 |
| 重置密码 | 任意账户,包括本人,无需原密码 | 子账号免原密码,本人需原密码 | 本人需原密码 |
| 积分充值、余额调整 | 任意账户 | 不允许 | 不允许 |
| 积分转移 | 向其他任意账户转出本人的积分 | 向直属非管理员子账号转出本人的积分 | 不允许 |
| 店铺续费、提交充值备注 | 任意账户 | 本人和直属非管理员子账号 | 本人 |
| 处理充值备注 | 任意账户 | 本人和直属非管理员子账号 | 不允许 |
| 管理员级别、计费配置、公共充值二维码 | 允许 | 不允许 | 不允许 |
管理员不受账户归属限制,仍须满足账户存在、余额充足等业务条件。删除要求无余额、无积分、无子账号、无店铺关联;本人满足条件也可删除,成功后注销会话。普通主账号不能向子账号授予自己没有的权限,不能通过管理具有管理员身份的子账号取得管理员权限。
## 校验与业务边界
DTO 用 `[Required]` 声明非空,使用数据注解和 `IValidatableObject` 声明输入规则。Service 入口统一调用 `RequestValidator.Validate`,续费通过 `ValidationBehavior` 调用 DTO 校验,保证内部调用也执行输入检查。Service 和后续管道只保留数据库状态、主子关系、权限、资金与店铺归属判断,不再重复校验必填字段。
账户登录名保持稳定,避免破坏店铺和历史流水关联。新建账户的主/子身份由接口决定,`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
```
连接现有 MySQL 前确认账户表用户名唯一、密码列可容纳 Identity 哈希、资金相关表支持事务。应用不自动创建或修改旧表。旧系统直接比较明文密码的登录接口不能识别新哈希,需随调用方迁移。
使用 `dotnet test Tests/Store.Users.Tests/Store.Users.Tests.csproj` 验证参数、权限、密码、资金和 HTTP 接口。SQLite 测试不能替代真实 MySQL 的并发与表结构联调。旧文件中的 E57 令牌、销售助手 Cookie、淘宝买手不属于本模块范围。可以继续使用“代码审查”检查实现质量。