test-report.md 36 KB

权限管理系统 (perms-system-server) — 测试报告

报告日期: 2026-04-16(第七轮,Expires 字段重命名 + 含义变更验证) 测试范围: API (go-zero REST, 全 POST) + gRPC (status codes) + Model 层 (_gen.go 模板生成 + 自定义方法) + Logic 单元测试 + util 层 + 访问控制 + UserDetailsLoader 测试用例设计详见 test-design.md


一、测试执行总览

指标 数值
测试用例总数 (test-design.md) 499
已覆盖 TC 数 498
未实现 TC 数 1 (TC-0189, 不可达防御分支, t.Skip)
测试函数总数 662
测试子用例总数 (含 table-driven) 744
测试包数量 23
✅ 通过 743 / 744
❌ 失败 0
⏭️ 跳过 1 (TC-0189 — 防御性不可达分支)

第七轮变更说明:

  • Expires 字段变更 ✅:ExpiresIn(过期秒数) → Expires(过期 unix 时间戳),REST/gRPC 同步更新
  • 更新了 TC-0001 (loginLogic)、TC-0013 (refreshTokenLogic)、TC-0165/TC-0172 (gRPC) 的断言逻辑
  • 至此 BUG-001 ~ BUG-004 及 WARN-001 全部修复,WARN-002 / WARN-003 为设计取舍不修改
  • 全部 743 个可执行测试子用例通过,0 失败

1.1 各包测试耗时

测试包 状态 耗时
handler/pub ✅ ok 2.475s
loaders ✅ ok 3.104s
logic/auth ✅ ok 8.033s
logic/dept ✅ ok 4.314s
logic/member ✅ ok 5.162s
logic/perm ✅ ok 5.819s
logic/product ✅ ok 6.947s
logic/pub ✅ ok 6.801s
logic/role ✅ ok 5.764s
logic/user ✅ ok 10.236s
middleware ✅ ok 8.668s
model/dept ✅ ok 7.094s
model/perm ✅ ok 7.932s
model/product ✅ ok 10.637s
model/productmember ✅ ok 12.484s
model/role ✅ ok 12.569s
model/roleperm ✅ ok 11.723s
model/user ✅ ok 11.735s
model/userperm ✅ ok 11.803s
model/userrole ✅ ok 11.483s
response ✅ ok 11.454s
server ✅ ok 11.790s
util ✅ ok 11.745s

二、TC 测试结果明细

2.1 REST API (TC-0001 ~ TC-0160)

TC编号 测试场景 测试结果
TC-0001 正常登录-不带productCode ✅ pass
TC-0002 正常登录-带productCode ✅ pass
TC-0003 超管登录+productCode ✅ pass
TC-0004 超管登录-无productCode ✅ pass
TC-0005 用户不存在 ✅ pass
TC-0006 DB异常(非ErrNotFound) ✅ pass
TC-0007 密码错误 ✅ pass
TC-0008 账号冻结 ✅ pass
TC-0009 非产品成员 ✅ pass
TC-0010 DEVELOPER成员 ✅ pass
TC-0011 SQL注入 ✅ pass
TC-0012 缺少必填字段 ✅ pass
TC-0013 正常刷新 ✅ pass
TC-0014 不带productCode(回退) ✅ pass
TC-0015 token无效 ✅ pass
TC-0016 用户已删除 ✅ pass
TC-0017 账号冻结 ✅ pass
TC-0018 超管+productCode ✅ pass
TC-0019 全部新增 ✅ pass
TC-0020 更新已有(名称变更) ✅ pass
TC-0021 无变化 ✅ pass
TC-0022 禁用权限重启 ✅ pass
TC-0023 移除不在列表的权限 ✅ pass
TC-0024 空perms数组 ✅ pass
TC-0025 验证disabled返回值 ✅ pass
TC-0026 appKey无效 ✅ pass
TC-0027 appSecret错误 ✅ pass
TC-0028 产品已禁用 ✅ pass
TC-0029 大批量(1000条) ✅ pass
TC-0030 正常获取-含productCode ✅ pass
TC-0031 不含productCode ✅ pass
TC-0032 未登录 ✅ pass
TC-0033 token过期 ✅ pass
TC-0034 userId=0 ✅ pass
TC-0035 正常修改 ✅ pass
TC-0036 mustChangePassword重置 ✅ pass
TC-0037 原密码错误 ✅ pass
TC-0038 新密码少于6字符 ✅ pass
TC-0039 新密码恰好6字符 ✅ pass
TC-0040 新密码空字符串 ✅ pass
TC-0041 新密码超过72字符 ✅ pass
TC-0042 新密码恰好72字符 ✅ pass
TC-0043 新旧密码相同 ✅ pass
TC-0044 用户不存在 ✅ pass
TC-0045 正常创建 ✅ pass
TC-0046 事务回滚-用户创建失败 ✅ pass
TC-0047 事务回滚-成员创建失败 ✅ pass
TC-0048 编码已存在 ✅ pass
TC-0049 并发创建同编码 ✅ pass
TC-0050 正常更新 ✅ pass
TC-0051 不存在 ✅ pass
TC-0052 不传status ✅ pass
TC-0053 正常分页 ✅ pass
TC-0054 默认分页 ✅ pass
TC-0055 pageSize超过上限 ✅ pass
TC-0056 pageSize=0 ✅ pass
TC-0057 page负值 ✅ pass
TC-0058 正常查询 ✅ pass
TC-0059 不存在 ✅ pass
TC-0060 创建顶级部门 ✅ pass
TC-0061 创建子部门 ✅ pass
TC-0062 父部门不存在 ✅ pass
TC-0063 不传DeptType默认NORMAL ✅ pass
TC-0064 传DeptType=DEV ✅ pass
TC-0065 事务内FindOneWithTx可见性 ✅ pass
TC-0066 事务回滚-Insert失败 ✅ pass
TC-0067 事务回滚-UpdateWithTx失败 ✅ pass
TC-0068 多层嵌套(5层) ✅ pass
TC-0069 通过Logic创建+验证Path ✅ pass
TC-0070 正常更新 ✅ pass
TC-0071 不存在 ✅ pass
TC-0072 DeptType NORMAL→DEV ✅ pass
TC-0073 DeptType无效值忽略 ✅ pass
TC-0074 正常删除(无子部门) ✅ pass
TC-0075 有子部门 ✅ pass
TC-0076 不存在的部门 ✅ pass
TC-0077 正常获取 ✅ pass
TC-0078 空数据 ✅ pass
TC-0079 孤儿节点 ✅ pass
TC-0080 正常查询 ✅ pass
TC-0081 默认分页 ✅ pass
TC-0082 pageSize超过上限 ✅ pass
TC-0083 不存在的productCode ✅ pass
TC-0084 正常创建 ✅ pass
TC-0085 重复角色名 ✅ pass
TC-0086 并发同名创建 ✅ pass
TC-0087 正常更新 ✅ pass
TC-0088 不存在 ✅ pass
TC-0089 正常查询 ✅ pass
TC-0090 pageSize超过上限 ✅ pass
TC-0091 正常查询 ✅ pass
TC-0092 不存在 ✅ pass
TC-0093 正常删除+级联 ✅ pass
TC-0094 事务回滚 ✅ pass
TC-0095 无关联数据 ✅ pass
TC-0096 正常绑定 ✅ pass
TC-0097 角色不存在 ✅ pass
TC-0098 清空权限 ✅ pass
TC-0099 重复permId ✅ pass
TC-0100 事务回滚 ✅ pass
TC-0101 正常创建 ✅ pass
TC-0102 用户名已存在(预检) ✅ pass
TC-0103 带完整可选字段 ✅ pass
TC-0104 非法email格式 ✅ pass
TC-0105 合法email ✅ pass
TC-0106 email为空(可选) ✅ pass
TC-0107 非法phone格式 ✅ pass
TC-0108 合法phone(国际) ✅ pass
TC-0109 phone为空(可选) ✅ pass
TC-0110 并发同username(TOCTOU) ✅ pass
TC-0111 唯一索引冲突消息 ✅ pass
TC-0112 正常更新 ✅ pass
TC-0113 不存在 ✅ pass
TC-0114 仅传id ✅ pass
TC-0115 清空nickname ✅ pass
TC-0116 清空email ✅ pass
TC-0117 清空remark ✅ pass
TC-0118 非法email格式 ✅ pass
TC-0119 非法phone格式 ✅ pass
TC-0120 合法phone ✅ pass
TC-0121 不传email(nil) ✅ pass
TC-0122 DeptId设为0(取消部门) ✅ pass
TC-0123 DeptId设为正值 ✅ pass
TC-0124 DeptId不传(nil) ✅ pass
TC-0125 含productCode ✅ pass
TC-0126 不含productCode ✅ pass
TC-0127 pageSize超过上限 ✅ pass
TC-0128 用户不在产品中 ✅ pass
TC-0129 批量查询DB异常 ✅ pass
TC-0130 正常查询 ✅ pass
TC-0131 正常查询-含Avatar ✅ pass
TC-0132 不存在 ✅ pass
TC-0133 正常绑定 ✅ pass
TC-0134 用户不存在 ✅ pass
TC-0135 清空角色 ✅ pass
TC-0136 事务回滚 ✅ pass
TC-0137 正常ALLOW ✅ pass
TC-0138 用户不存在 ✅ pass
TC-0139 DENY权限 ✅ pass
TC-0140 清空权限 ✅ pass
TC-0141 正常冻结 ✅ pass
TC-0142 正常解冻 ✅ pass
TC-0143 非法status(0) ✅ pass
TC-0144 冻结自己 ✅ pass
TC-0145 冻结超管 ✅ pass
TC-0146 正常添加 ✅ pass
TC-0147 产品不存在 ✅ pass
TC-0148 用户不存在 ✅ pass
TC-0149 已是成员 ✅ pass
TC-0150 并发添加 ✅ pass
TC-0151 正常更新 ✅ pass
TC-0152 不存在 ✅ pass
TC-0153 正常查询(批量查用户) ✅ pass
TC-0154 成员用户已删除 ✅ pass
TC-0155 pageSize超过上限 ✅ pass
TC-0156 空成员列表 ✅ pass
TC-0157 正常移除+级联(事务内) ✅ pass
TC-0158 跨产品隔离 ✅ pass
TC-0159 成员不存在 ✅ pass
TC-0160 事务回滚 ✅ pass

2.2 gRPC 接口 (TC-0161 ~ TC-0183)

TC编号 测试场景 测试结果
TC-0161 正常同步 ✅ pass
TC-0162 appKey无效 ✅ pass
TC-0163 appSecret错误 ✅ pass
TC-0164 产品已禁用 ✅ pass
TC-0165 验证disabled计数 ✅ pass
TC-0166 正常登录(无productCode) ✅ pass
TC-0167 用户不存在 ✅ pass
TC-0168 密码错误 ✅ pass
TC-0169 账号冻结 ✅ pass
TC-0170 超管+productCode ✅ pass
TC-0171 普通用户+productCode ✅ pass
TC-0172 正常刷新 ✅ pass
TC-0173 token无效 ✅ pass
TC-0174 账号冻结 ✅ pass
TC-0175 productCode回退到claims ✅ pass
TC-0176 超管+productCode ✅ pass
TC-0177 普通用户+productCode ✅ pass
TC-0178 有效token ✅ pass
TC-0179 无效token ✅ pass
TC-0180 缺少userId ✅ pass
TC-0181 用户不存在 ✅ pass
TC-0182 超管 ✅ pass
TC-0183 MEMBER-DENY覆盖 ✅ pass

2.3 中间件 / 统一响应 / util (TC-0184 ~ TC-0266, TC-0434, TC-0478 ~ TC-0480)

TC编号 测试场景 测试结果
TC-0184 正常Bearer token ✅ pass
TC-0185 无Authorization头 ✅ pass
TC-0186 无Bearer前缀 ✅ pass
TC-0187 token签名错误 ✅ pass
TC-0188 token过期 ✅ pass
TC-0189 claims类型断言失败 ⏭️ skip(!ok 防御性分支不可达,jwt.ParseWithClaims 始终返回 *Claims)
TC-0434 refresh token被拒绝 ✅ pass
TC-0478 冻结用户被403 ✅ pass
TC-0479 用户不存在(Status=0) ✅ pass
TC-0480 UserDetails注入context ✅ pass
TC-0190 业务错误(CodeError) ✅ pass
TC-0191 内部错误 ✅ pass
TC-0192 成功(有data) ✅ pass
TC-0193 成功(无data) ✅ pass
TC-0194 正常值 ✅ pass
TC-0195 page<=0 ✅ pass
TC-0196 page=-1 ✅ pass
TC-0197 pageSize<=0 ✅ pass
TC-0198 pageSize>100 ✅ pass
TC-0199 pageSize=100 ✅ pass
TC-0200 pageSize=101 ✅ pass
TC-0201 双零 ✅ pass
TC-0202 正常邮箱 ✅ pass
TC-0203 含点号 ✅ pass
TC-0204 含加号 ✅ pass
TC-0205 缺少@ ✅ pass
TC-0206 缺少域名 ✅ pass
TC-0207 缺少TLD ✅ pass
TC-0208 空字符串 ✅ pass
TC-0209 国内手机号 ✅ pass
TC-0210 带+国际码 ✅ pass
TC-0211 太短(6位) ✅ pass
TC-0212 恰好7位 ✅ pass
TC-0213 最长15位 ✅ pass
TC-0214 超长16位 ✅ pass
TC-0215 包含字母 ✅ pass
TC-0216 空字符串 ✅ pass
TC-0217 正常生成 ✅ pass
TC-0218 解析token验证claims ✅ pass
TC-0219 空secret ✅ pass
TC-0220 空perms ✅ pass
TC-0221 过期时间验证 ✅ pass
TC-0222 正常生成 ✅ pass
TC-0223 解析验证 ✅ pass
TC-0224 productCode为空 ✅ pass
TC-0225 正常解析 ✅ pass
TC-0226 错误secret ✅ pass
TC-0227 无效token字符串 ✅ pass
TC-0228 空token ✅ pass
TC-0229 过期token ✅ pass
TC-0230 AccessToken误用 ✅ pass
TC-0231 超管 ✅ pass
TC-0232 超管+查询失败 ✅ pass
TC-0233 非产品成员 ✅ pass
TC-0234 成员查询失败(非ErrNotFound) ✅ pass
TC-0235 DEVELOPER成员 ✅ pass
TC-0236 ADMIN成员 ✅ pass
TC-0237 DEVELOPER+查询失败 ✅ pass
TC-0238 MEMBER-DEV部门-全权限 ✅ pass
TC-0239 MEMBER-DEV部门-查询权限失败 ✅ pass
TC-0240 MEMBER-非DEV部门-正常回退 ✅ pass
TC-0241 MEMBER-部门不存在-正常回退 ✅ pass
TC-0242 MEMBER-deptId=0-跳过部门检查 ✅ pass
TC-0243 MEMBER-无角色无自定义 ✅ pass
TC-0244 MEMBER-有角色权限 ✅ pass
TC-0245 MEMBER-角色跨产品过滤 ✅ pass
TC-0246 MEMBER-角色已禁用 ✅ pass
TC-0247 MEMBER-ALLOW添加 ✅ pass
TC-0248 MEMBER-DENY排除角色权限 ✅ pass
TC-0249 MEMBER-DENY排除ALLOW ✅ pass
TC-0250 MEMBER-ALLOW+角色去重 ✅ pass
TC-0251 MEMBER-最终perm.Status=2 ✅ pass
TC-0252 MEMBER-FindRoleIdsByUserId失败 ✅ pass
TC-0253 MEMBER-FindByIds(roles)失败 ✅ pass
TC-0254 MEMBER-FindPermIdsByRoleIds失败 ✅ pass
TC-0255 MEMBER-FindPermIdsByUserIdAndEffect(ALLOW)失败 ✅ pass
TC-0256 MEMBER-FindPermIdsByUserIdAndEffect(DENY)失败 ✅ pass
TC-0257 MEMBER-FindByIds(perms)失败 ✅ pass
TC-0258 GetUserId-正常 ✅ pass
TC-0259 GetUserId-空ctx ✅ pass
TC-0260 GetUsername-正常 ✅ pass
TC-0261 GetUsername-空ctx ✅ pass
TC-0262 GetProductCode-正常 ✅ pass
TC-0263 GetMemberType-正常 ✅ pass
TC-0264 IsSuperAdmin-是 ✅ pass
TC-0265 IsSuperAdmin-否 ✅ pass
TC-0266 IsSuperAdmin-空 ✅ pass

2.4 Model 层 _gen.go 通用方法 (TC-0267 ~ TC-0356)

以下每个 TC 为通用模式,适用于全部 9 个 Model,实际测试函数数 = TC × 模型数。

CRUD / 事务 / 批量方法 (TC-0267 ~ TC-0310):

TC编号 测试场景 测试结果
TC-0267 正常插入 ✅ pass
TC-0268 唯一索引冲突 ✅ pass
TC-0269 缓存key生成正确 ✅ pass
TC-0270 事务内插入 ✅ pass
TC-0271 事务回滚后无数据 ✅ pass
TC-0272 正常查询(缓存未命中) ✅ pass
TC-0273 正常查询(缓存命中) ✅ pass
TC-0274 记录不存在 ✅ pass
TC-0275 DB异常(非ErrNotFound) ✅ pass
TC-0276 事务内正常查询 ✅ pass
TC-0277 事务内记录不存在 ✅ pass
TC-0278 事务内可见性 ✅ pass
TC-0279 正常更新 ✅ pass
TC-0280 记录不存在 ✅ pass
TC-0281 事务内更新 ✅ pass
TC-0282 正常删除 ✅ pass
TC-0283 记录不存在 ✅ pass
TC-0284 事务内删除 ✅ pass
TC-0285 正常事务 ✅ pass
TC-0286 fn返回错误 ✅ pass
TC-0287 获取表名 ✅ pass
TC-0288 空列表 ✅ pass
TC-0289 单条记录 ✅ pass
TC-0290 多条记录(3条) ✅ pass
TC-0291 唯一索引冲突 ✅ pass
TC-0292 大批量(1000条) ✅ pass
TC-0293 空列表 ✅ pass
TC-0294 正常多条 ✅ pass
TC-0295 事务回滚 ✅ pass
TC-0296 空列表 ✅ pass
TC-0297 单条记录 ✅ pass
TC-0298 多条记录(3条) ✅ pass
TC-0299 部分id不存在 ✅ pass
TC-0300 空列表 ✅ pass
TC-0301 正常多条 ✅ pass
TC-0302 单条 ✅ pass
TC-0303 多条 ✅ pass
TC-0304 vals数量正确 ✅ pass
TC-0305 空ids ✅ pass
TC-0306 单个id ✅ pass
TC-0307 多个id(3个) ✅ pass
TC-0308 包含不存在id ✅ pass
TC-0309 空ids ✅ pass
TC-0310 正常多条 ✅ pass

唯一索引方法明细 (TC-0311 ~ TC-0346):

TC编号 Model 方法 测试场景 测试结果
TC-0311 SysUser FindOneByUsername 正常查询 ✅ pass
TC-0312 SysUser FindOneByUsername 不存在 ✅ pass
TC-0313 SysUser FindOneByUsernameWithTx 事务内正常查询 ✅ pass
TC-0314 SysUser FindOneByUsernameWithTx 事务内不存在 ✅ pass
TC-0315 SysProduct FindOneByAppKey 正常查询 ✅ pass
TC-0316 SysProduct FindOneByAppKey 不存在 ✅ pass
TC-0317 SysProduct FindOneByAppKeyWithTx 事务内正常查询 ✅ pass
TC-0318 SysProduct FindOneByAppKeyWithTx 事务内不存在 ✅ pass
TC-0319 SysProduct FindOneByCode 正常查询 ✅ pass
TC-0320 SysProduct FindOneByCode 不存在 ✅ pass
TC-0321 SysProduct FindOneByCodeWithTx 事务内正常查询 ✅ pass
TC-0322 SysProduct FindOneByCodeWithTx 事务内不存在 ✅ pass
TC-0323 SysPerm FindOneByProductCodeCode 正常查询 ✅ pass
TC-0324 SysPerm FindOneByProductCodeCode 不存在 ✅ pass
TC-0325 SysPerm FindOneByProductCodeCodeWithTx 事务内正常查询 ✅ pass
TC-0326 SysPerm FindOneByProductCodeCodeWithTx 事务内不存在 ✅ pass
TC-0327 SysRole FindOneByProductCodeName 正常查询 ✅ pass
TC-0328 SysRole FindOneByProductCodeName 不存在 ✅ pass
TC-0329 SysRole FindOneByProductCodeNameWithTx 事务内正常查询 ✅ pass
TC-0330 SysRole FindOneByProductCodeNameWithTx 事务内不存在 ✅ pass
TC-0331 SysRolePerm FindOneByRoleIdPermId 正常查询 ✅ pass
TC-0332 SysRolePerm FindOneByRoleIdPermId 不存在 ✅ pass
TC-0333 SysRolePerm FindOneByRoleIdPermIdWithTx 事务内正常查询 ✅ pass
TC-0334 SysRolePerm FindOneByRoleIdPermIdWithTx 事务内不存在 ✅ pass
TC-0335 SysUserPerm FindOneByUserIdPermId 正常查询 ✅ pass
TC-0336 SysUserPerm FindOneByUserIdPermId 不存在 ✅ pass
TC-0337 SysUserPerm FindOneByUserIdPermIdWithTx 事务内正常查询 ✅ pass
TC-0338 SysUserPerm FindOneByUserIdPermIdWithTx 事务内不存在 ✅ pass
TC-0339 SysUserRole FindOneByUserIdRoleId 正常查询 ✅ pass
TC-0340 SysUserRole FindOneByUserIdRoleId 不存在 ✅ pass
TC-0341 SysUserRole FindOneByUserIdRoleIdWithTx 事务内正常查询 ✅ pass
TC-0342 SysUserRole FindOneByUserIdRoleIdWithTx 事务内不存在 ✅ pass
TC-0343 SysProductMember FindOneByProductCodeUserId 正常查询 ✅ pass
TC-0344 SysProductMember FindOneByProductCodeUserId 不存在 ✅ pass
TC-0345 SysProductMember FindOneByProductCodeUserIdWithTx 事务内正常查询 ✅ pass
TC-0346 SysProductMember FindOneByProductCodeUserIdWithTx 事务内不存在 ✅ pass

内部辅助方法 (TC-0347 ~ TC-0356):

TC编号 测试场景 测试结果 未实现原因
TC-0347 空ids ✅ pass role 同包测试可访问私有函数
TC-0348 正常ids ✅ pass role 同包测试
TC-0349 部分不存在 ✅ pass role 同包测试
TC-0350 DB异常 ✅ pass 坏连接模拟
TC-0351 正常 ✅ pass role 同包测试
TC-0352 正常 ✅ pass role 同包测试
TC-0353 正常 ✅ pass role 同包测试
TC-0354 cachePrefix为空 ✅ pass role 同包测试
TC-0355 cachePrefix非空 ✅ pass role 同包测试
TC-0356 多唯一索引前缀(SysProduct) ✅ pass product 同包测试

2.5 Model 层自定义方法 (TC-0357 ~ TC-0433)

TC编号 测试场景 测试结果
TC-0357 正常分页 ✅ pass
TC-0358 第二页 ✅ pass
TC-0359 空表 ✅ pass
TC-0360 count查询失败 ✅ pass
TC-0361 list查询失败 ✅ pass
TC-0362 正常查询 ✅ pass
TC-0363 空deptIds ✅ pass
TC-0364 单个deptId ✅ pass
TC-0365 deptId不存在 ✅ pass
TC-0366 正常批量查询 ✅ pass
TC-0367 空ids ✅ pass
TC-0368 部分id不存在 ✅ pass
TC-0369 DB异常 ✅ pass
TC-0370 正常分页 ✅ pass
TC-0371 空表 ✅ pass
TC-0372 count失败 ✅ pass
TC-0373 正常分页 ✅ pass
TC-0374 不存在的productCode ✅ pass
TC-0375 正常查询(仅status=1) ✅ pass
TC-0376 无启用权限 ✅ pass
TC-0377 正常查询 ✅ pass
TC-0378 空结果 ✅ pass
TC-0379 正常 ✅ pass
TC-0380 空ids ✅ pass
TC-0381 正常查询 ✅ pass
TC-0382 空结果 ✅ pass
TC-0383 key唯一性 ✅ pass
TC-0384 codes非空-正常 ✅ pass
TC-0385 codes为空-全部禁用 ✅ pass
TC-0386 无需禁用 ✅ pass
TC-0387 DB异常 ✅ pass
TC-0388 正常查询 ✅ pass
TC-0389 空表 ✅ pass
TC-0390 正常查询 ✅ pass
TC-0391 无子部门 ✅ pass
TC-0392 正常查询 ✅ pass
TC-0393 LIKE注入已阻止 ✅ pass
TC-0394 无匹配 ✅ pass
TC-0395 正常分页 ✅ pass
TC-0396 空结果 ✅ pass
TC-0397 正常 ✅ pass
TC-0398 空ids ✅ pass
TC-0399 正常查询 ✅ pass
TC-0400 无绑定 ✅ pass
TC-0401 正常查询 ✅ pass
TC-0402 空roleIds ✅ pass
TC-0403 去重验证 ✅ pass
TC-0404 正常删除 ✅ pass
TC-0405 无绑定 ✅ pass
TC-0406 正常事务内删除 ✅ pass
TC-0407 正常查询 ✅ pass
TC-0408 无记录 ✅ pass
TC-0409 ALLOW ✅ pass
TC-0410 DENY ✅ pass
TC-0411 无记录 ✅ pass
TC-0412 正常删除 ✅ pass
TC-0413 事务内删除 ✅ pass
TC-0414 正常删除 ✅ pass
TC-0415 跨产品隔离 ✅ pass
TC-0416 事务内跨产品删除 ✅ pass
TC-0417 正常查询 ✅ pass
TC-0418 无绑定 ✅ pass
TC-0419 正常查询 ✅ pass
TC-0420 正常删除 ✅ pass
TC-0421 事务内删除 ✅ pass
TC-0422 正常删除 ✅ pass
TC-0423 正常删除 ✅ pass
TC-0424 跨产品隔离 ✅ pass
TC-0425 事务内跨产品删除 ✅ pass
TC-0426 正常分页 ✅ pass
TC-0427 空结果 ✅ pass
TC-0428 正常查询 ✅ pass
TC-0429 无成员身份 ✅ pass
TC-0430 正常批量 ✅ pass
TC-0431 空userIds ✅ pass
TC-0432 部分不是成员 ✅ pass
TC-0433 map key正确 ✅ pass

2.6 访问控制 access.go (TC-0435 ~ TC-0457) 🆕

TC编号 测试场景 测试结果
TC-0435 RequireSuperAdmin-超管通过 ✅ pass
TC-0436 RequireSuperAdmin-ADMIN拒绝 ✅ pass
TC-0437 RequireSuperAdmin-MEMBER拒绝 ✅ pass
TC-0438 RequireSuperAdmin-未登录 ✅ pass
TC-0439 RequireProductAdmin-超管通过 ✅ pass
TC-0440 RequireProductAdmin-ADMIN通过 ✅ pass
TC-0441 RequireProductAdmin-DEVELOPER拒绝 ✅ pass
TC-0442 RequireProductAdmin-MEMBER拒绝 ✅ pass
TC-0443 RequireProductAdmin-未登录 ✅ pass
TC-0444 CheckMemberTypeAssignment-超管分配任何类型 ✅ pass
TC-0445 CheckMemberTypeAssignment-ADMIN分配DEVELOPER ✅ pass
TC-0446 CheckMemberTypeAssignment-同级拒绝 ✅ pass
TC-0447 CheckMemberTypeAssignment-越级拒绝 ✅ pass
TC-0448 CheckMemberTypeAssignment-MEMBER同级拒绝 ✅ pass
TC-0449 CheckMemberTypeAssignment-未登录 ✅ pass
TC-0450 CheckManageAccess-超管可管理任何人 ✅ pass
TC-0451 CheckManageAccess-操作自己 ✅ pass
TC-0452 CheckManageAccess-ADMIN跳过部门检查 ✅ pass
TC-0453 CheckManageAccess-无部门拒绝 ✅ pass
TC-0454 CheckManageAccess-目标用户无部门 ✅ pass
TC-0455 CheckManageAccess-不同部门拒绝 ✅ pass
TC-0456 CheckManageAccess-未登录 ✅ pass
TC-0457 memberTypePriority-全类型验证 ✅ pass

2.7 UserDetailsLoader (TC-0458 ~ TC-0477) 🆕

TC编号 测试场景 测试结果
TC-0458 Load-DB加载(缓存miss) ✅ pass
TC-0459 Load-缓存命中 ✅ pass
TC-0460 Load-用户不存在 ✅ pass
TC-0461 Load-productCode为空 ✅ pass
TC-0462 Del删除指定缓存 ✅ pass
TC-0463 Clean清除用户所有产品缓存 ✅ pass(BUG-004 已修复)
TC-0464 CleanByProduct清除产品所有用户 ✅ pass(BUG-004 已修复)
TC-0465 BatchDel批量删除 ✅ pass
TC-0466 BatchDel空数组 ✅ pass
TC-0467 loadPerms-超管全量权限 ✅ pass
TC-0468 loadPerms-ADMIN全量权限 ✅ pass
TC-0469 loadPerms-DEVELOPER全量权限 ✅ pass
TC-0470 loadPerms-DEV部门全量权限 ✅ pass
TC-0471 loadPerms-MEMBER角色权限+ALLOW-DENY ✅ pass
TC-0472 loadRoles-多角色取最小permsLevel ✅ pass
TC-0473 loadRoles-无角色 ✅ pass
TC-0474 loadRoles-角色跨产品过滤 ✅ pass
TC-0475 loadRoles-禁用角色不计入 ✅ pass
TC-0476 loadMembership-超管自动SUPER_ADMIN ✅ pass
TC-0477 loadMembership-非成员MemberType为空 ✅ pass

2.8 Logic 层访问控制负面测试 (TC-0481 ~ TC-0491) 🆕

TC编号 测试场景 测试结果
TC-0481 createDept-非超管拒绝 ✅ pass
TC-0482 updateDept-非超管拒绝 ✅ pass
TC-0483 deleteDept-非超管拒绝 ✅ pass
TC-0484 createProduct-非超管拒绝 ✅ pass
TC-0485 updateProduct-非超管拒绝 ✅ pass
TC-0486 createUser-非产品管理员拒绝 ✅ pass
TC-0487 createRole-非产品管理员拒绝 ✅ pass
TC-0488 updateRole-非产品管理员拒绝 ✅ pass
TC-0489 deleteRole-非产品管理员拒绝 ✅ pass
TC-0490 bindRolePerms-非产品管理员拒绝 ✅ pass
TC-0491 updateUser-非本人非超管拒绝 ✅ pass

2.9 Model 层新增方法 (TC-0492 ~ TC-0499) 🆕

TC编号 测试场景 测试结果
TC-0492 FindMinPermsLevelByUserIdAndProductCode-正常 ✅ pass(BUG-003 已修复)
TC-0493 FindMinPermsLevelByUserIdAndProductCode-无角色 ✅ pass(BUG-003 已修复)
TC-0494 FindAllCodesByProductCode-正常 ✅ pass
TC-0495 FindAllCodesByProductCode-无权限 ✅ pass
TC-0496 FindIdsByDeptId-正常 ✅ pass
TC-0497 FindIdsByDeptId-空部门 ✅ pass
TC-0498 FindUserIdsByRoleId-正常 ✅ pass
TC-0499 FindUserIdsByRoleId-无绑定 ✅ pass

三、源码审计

3.1 历史修复确认 (v1→v7)

# 原始隐患 修复轮次 最终状态
BindRoles/BindPerms/SetPerms 非事务 v2 ✅ TransactCtx + *WithTx
DeleteRole 无级联删除 v2 ✅ 事务内三步级联
RemoveMember 无级联清理 v2→v3 ✅ v2增加ForProduct; v3升级事务
UpdateUserStatus 无校验 v2 ✅ status∈{1,2}+自我保护+超管保护
SyncPerms N+1 查询 v2 ✅ FindMapByProductCode+批量
CreateProduct 非事务 v2 ✅ TransactCtx
GetUserPerms 冗余查询 v2 ✅ isSuperAdmin参数
错误信息泄露 v2 ✅ 统一"服务器内部错误"+logx
VerifyToken 断言无保护 v2 ✅ ok检查
addMember 不校验产品/用户存在性 v3 ✅ FindOneByCode+FindOne预检
bindRoles/bindPerms/setPerms 不校验目标存在性 v3 ✅ FindOne预检
changePassword 新旧相同/截断 v3 ✅ len>72+相同密码校验
CreateDept 非事务 v3 ✅ TransactCtx
gRPC errors.New 非规范 v3 ✅ status.Error(codes.Xxx)
SyncPerms 不返回 disabled v3 ✅ DisableNotInCodes返回int64
RemoveMember 三步非事务 v3 ✅ TransactCtx+*ForProductTx
全部路由改POST v3 ✅ perm.api统一POST
updateUser 无法清空字段 v4 ✅ *string 指针类型
pageSize 无上限 v4 ✅ NormalizePage cap 100
createUser TOCTOU 错误不友好 v4 ✅ 捕获 Duplicate entry→ErrConflict
email/phone 无格式校验 v4 ✅ util.IsValidEmail/IsValidPhone
changePassword 新密码允许空字符串 v4 ✅ len<6 最小长度校验
createRole 重复角色名返回500 v5 ✅ 捕获 Duplicate entry→ErrConflict
memberList N+1 查用户 v5 ✅ FindByIds批量查询+map
userList N+1 查成员类型 v5 ✅ FindMapByProductCodeUserIds批量
updateUser DeptId无法清零 v5 ✅ *int64 指针类型
createDeptLogic 事务内 FindOne 隔离 bug v6 ✅ FindOne→FindOneWithTx(session)
Model _gen.go 新增 FindOneWithTx / FindOneBy...WithTx v6 ✅ 16 个新事务查询方法
DeptType 字段新增 v6 ✅ 创建/更新/树逻辑+consts
GetUserPerms DEV 部门全权限分支 v6 ✅ deptId参数+DeptTypeDev检查
BUG-001: Handler 参数校验返回 500 v7 ✅ ErrBadRequest
BUG-002: JWT token 类型无区分 v7 ✅ TokenType 字段
FindByPathPrefix LIKE 注入 v7 ✅ NewReplacer 转义
BUG-003: FindMinPermsLevel sql.NullInt64 不兼容 v8 ✅ IFNULL+int64
BUG-004: cleanByPattern Lua SCAN cursor 类型不匹配 v9 ✅ tonumber(nextCursor)
refreshToken 无限续期安全隐患 v10 ✅ 不再重新生成 refreshToken,原样返回
refreshToken 从 body 改为 header 获取 v10 header:"Authorization"
ExpiresIn → Expires 字段重命名+含义变更 v11 ✅ 秒数→unix时间戳

3.2 v8 新增模块审计(access 控制 + UserDetailsLoader)

新增文件

文件 说明 审计结论
internal/loaders/userDetailsLoader.go 用户详情加载器 + Redis 缓存 见下方详细分析
internal/logic/auth/access.go 集中访问控制函数 逻辑正确

access.go 审计结论

函数 审计结论
RequireSuperAdmin ✅ 正确:nil 检查 → IsSuperAdmin 检查
RequireProductAdmin ✅ 正确:nil → SuperAdmin → Admin → 拒绝
CheckMemberTypeAssignment ✅ 正确:SuperAdmin 豁免,优先级比较用 >= 阻止同级分配
CheckManageAccess ✅ 正确:SuperAdmin/Self 豁免 → 部门层级 → 权限级别
checkDeptHierarchy ✅ 正确:ADMIN 豁免,DeptId=0 检查,HasPrefix 子部门判断
checkPermLevel ✅ 正确:memberType 优先级 → permsLevel 比较
memberTypePriority ✅ 正确:SA=0, A=1, D=2, M=3, unknown=MaxInt32

UserDetailsLoader 审计发现

# 发现 风险等级 说明
BUG-003 FindMinPermsLevelByUserIdAndProductCode 使用 sql.NullInt64 与 go-zero 不兼容 🔴 高 已修复 (v9):改为 IFNULL(MIN(...), -1) + int64,level < 0 时返回 ErrNotFound。TC-0492、TC-0493 恢复通过。
WARN-001 cleanByPattern 使用 Redis KEYS 命令 ⚠️ 中 已修改 (v9):改用 Lua 脚本 + SCAN 替代 KEYS。但引入 BUG-004(见下)。
BUG-004 cleanByPattern Lua SCAN cursor 类型断言失败 🟡 中 已修复 (v10):Lua 脚本中 return nextCursor 改为 return tonumber(nextCursor),Go 侧 val.(int64) 断言恢复正常。TC-0463、TC-0464 通过。
WARN-002 Load 对不存在用户返回 Status=0 ℹ️ 低 loadUser 失败(用户不存在/DB 错误),UserDetails.Status 为零值 0,中间件检查 Status != StatusEnabled(1) 会返回 403 "账号已被冻结"。错误消息不够精确(应为 "用户不存在"),但安全性正确(不存在用户被拒绝)。
WARN-003 loadPerms 错误被静默吞掉 ℹ️ 低 FindAllCodesByProductCode 失败时仅 logx.Errorf,Perms 为 nil。虽有日志但调用方无法感知失败。当前设计为 "尽力加载",不影响安全性(权限为空 = 无权限)。

中间件变更审计

变更 审计结论
新增 loader.Load() 调用 ✅ 正确:每次请求加载最新用户详情
冻结账号 403 拦截 ✅ 正确:ud.Status != consts.StatusEnabled
UserDetails 注入 context ✅ 正确:替代旧的多个 context key
公共 helper 函数 ✅ 正确:GetUserDetails/GetUserId/GetUsername/GetProductCode/GetMemberType/IsSuperAdmin

Logic 层 access 控制接入审计

Logic access 检查 缓存失效 审计结论
createDept RequireSuperAdmin
updateDept RequireSuperAdmin Clean(dept 下所有用户)
deleteDept RequireSuperAdmin
createProduct RequireSuperAdmin
updateProduct RequireSuperAdmin CleanByProduct
createUser RequireProductAdmin
updateUser Self 或 SuperAdmin Clean(userId)
updateUserStatus CheckManageAccess Clean(userId)
bindRoles CheckManageAccess Del(userId, productCode)
setUserPerms CheckManageAccess Del(userId, productCode)
createRole RequireProductAdmin
updateRole RequireProductAdmin BatchDel(affectedUsers)
deleteRole RequireProductAdmin BatchDel(affectedUsers)
bindRolePerms RequireProductAdmin BatchDel(affectedUsers)
addMember CheckManageAccess + CheckMemberTypeAssignment Del(userId, productCode)
updateMember CheckManageAccess + CheckMemberTypeAssignment Del(userId, productCode)
removeMember CheckManageAccess Del(userId, productCode)
login — (公开) Load (查询)
refreshToken — (公开) Load (查询)
syncPerms appKey/appSecret 校验 CleanByProduct
userInfo — (中间件已鉴权)

3.3 BUG-003 ✅ 已修复

  • 关联 TC: TC-0492、TC-0493
  • 位置: internal/model/role/sysRoleModel.goFindMinPermsLevelByUserIdAndProductCode
  • 修复方案: DEV 改为 IFNULL(MIN(r.permsLevel), -1) + 普通 int64 扫描,level < 0 时返回 ErrNotFound
  • 验证结果: TC-0492、TC-0493 全部通过 ✅

3.4 BUG-004 ✅ 已修复

  • 关联 TC: TC-0463、TC-0464
  • 位置: internal/loaders/userDetailsLoader.gocleanByPattern
  • 修复方案: DEV 在 Lua 脚本中将 return nextCursor 改为 return tonumber(nextCursor),使返回值为数字类型,Go 侧 val.(int64) 断言恢复正常
  • 验证结果: TC-0463、TC-0464 全部通过 ✅

四、代码质量总评

经过三轮审计,本次新增的 access 控制和 UserDetailsLoader 实现质量良好:

  • 访问控制架构: 集中式 access.go 管控,4 个关键函数覆盖超管/产品管理员/成员类型/部门层级/权限级别等维度
  • 缓存策略: UserDetailsLoader 采用 Redis 缓存 + TTL(300s) + 主动失效,所有写操作均有对应的 Del/Clean/BatchDel
  • 安全纵深: JWT 中间件 → UserDetailsLoader 实时加载 → 冻结账号拦截 → Logic 层 access 检查,四层防护
  • 部门层级管控: HasPrefix 子部门判断 + ADMIN 豁免 + DeptId=0 边界处理
  • 权限级别比较: memberType 优先级 + permsLevel 数值双重比较,确保低级别用户无法管理高级别用户
  • BUG-003: ✅ 已修复,FindMinPermsLevelByUserIdAndProductCode 改为 IFNULL + int64
  • WARN-001: ✅ 已改用 Lua + SCAN 替代 KEYS
  • BUG-004: ✅ 已修复,Lua 脚本 return tonumber(nextCursor)
  • WARN-002 / WARN-003: DEV 确认为设计取舍,安全性不受影响,不修改

测试覆盖统计

指标 数值
TC 总数 499
已实现 498 (99.8%)
跳过 1 (TC-0189,!ok 防御性不可达分支)
测试函数 662
测试子用例 744
✅ 通过 743
❌ 失败 0
⏭️ 跳过 1 (TC-0189 — t.Skip)
通过率 100% (743/743)
BUG-001 ~ BUG-004 ✅ 全部已修复
WARN-001 ✅ 已修复(KEYS → Lua SCAN)
WARN-002 / WARN-003 设计取舍,不修改