getUserPermsLogic_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package user
  2. import (
  3. "errors"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "perms-system-server/internal/consts"
  9. memberModel "perms-system-server/internal/model/productmember"
  10. "perms-system-server/internal/response"
  11. "perms-system-server/internal/svc"
  12. "perms-system-server/internal/testutil"
  13. "perms-system-server/internal/testutil/ctxhelper"
  14. "perms-system-server/internal/types"
  15. )
  16. // insertTestMemberWithType 创建指定类型的产品成员,供 getUserPerms 测试使用。
  17. func insertTestMemberWithType(t *testing.T, svcCtx *svc.ServiceContext, productCode string, userId int64, memberType string) int64 {
  18. t.Helper()
  19. now := time.Now().Unix()
  20. res, err := svcCtx.SysProductMemberModel.Insert(ctxhelper.SuperAdminCtx(), &memberModel.SysProductMember{
  21. ProductCode: productCode,
  22. UserId: userId,
  23. MemberType: memberType,
  24. Status: consts.StatusEnabled,
  25. CreateTime: now,
  26. UpdateTime: now,
  27. })
  28. require.NoError(t, err)
  29. id, _ := res.LastInsertId()
  30. return id
  31. }
  32. // insertUserPerm 直接向 sys_user_perm 插入一条覆盖记录,绕过 SetUserPerms 的业务校验。
  33. func insertUserPerm(t *testing.T, svcCtx *svc.ServiceContext, userId, permId int64, effect string) {
  34. t.Helper()
  35. conn := testutil.GetTestSqlConn()
  36. now := time.Now().Unix()
  37. _, err := conn.ExecCtx(ctxhelper.SuperAdminCtx(),
  38. "INSERT INTO `sys_user_perm` (`userId`,`permId`,`effect`,`createTime`,`updateTime`) VALUES (?,?,?,?,?)",
  39. userId, permId, effect, now, now)
  40. require.NoError(t, err)
  41. }
  42. // TC-1257: 超管查任意用户权限覆盖(必须传 productCode)
  43. func TestGetUserPerms_SuperAdmin(t *testing.T) {
  44. ctx := ctxhelper.SuperAdminCtx()
  45. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  46. conn := testutil.GetTestSqlConn()
  47. username := testutil.UniqueId()
  48. userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass"))
  49. mId := insertTestMember(t, svcCtx, "test_product", userId)
  50. permId := insertTestPerm(t, svcCtx, "test_product")
  51. insertUserPerm(t, svcCtx, userId, permId, consts.PermEffectAllow)
  52. t.Cleanup(func() {
  53. testutil.CleanTableByField(ctx, conn, "`sys_user_perm`", "userId", userId)
  54. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  55. testutil.CleanTable(ctx, conn, "`sys_user`", userId)
  56. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  57. })
  58. resp, err := NewGetUserPermsLogic(ctx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: userId, ProductCode: "test_product"})
  59. require.NoError(t, err)
  60. require.NotNil(t, resp)
  61. require.Len(t, resp.Perms, 1)
  62. assert.Equal(t, permId, resp.Perms[0].PermId)
  63. assert.Equal(t, consts.PermEffectAllow, resp.Perms[0].Effect)
  64. }
  65. // TC-1304: 超管不传 productCode 时必须返回 400
  66. func TestGetUserPerms_SuperAdmin_MissingProductCode(t *testing.T) {
  67. ctx := ctxhelper.SuperAdminCtx()
  68. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  69. _, err := NewGetUserPermsLogic(ctx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: 1})
  70. require.Error(t, err)
  71. var ce *response.CodeError
  72. require.True(t, errors.As(err, &ce))
  73. assert.Equal(t, 400, ce.Code())
  74. assert.Contains(t, ce.Error(), "必须指定产品编码")
  75. }
  76. // TC-1259: 产品 ADMIN 查同产品 MEMBER 的权限覆盖
  77. func TestGetUserPerms_AdminQueriesMember(t *testing.T) {
  78. bootstrapCtx := ctxhelper.SuperAdminCtx()
  79. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  80. conn := testutil.GetTestSqlConn()
  81. username := testutil.UniqueId()
  82. userId := insertTestUser(t, bootstrapCtx, username, testutil.HashPassword("pass"))
  83. mId := insertTestMember(t, svcCtx, "test_product", userId) // MEMBER 类型
  84. permId := insertTestPerm(t, svcCtx, "test_product")
  85. insertUserPerm(t, svcCtx, userId, permId, consts.PermEffectAllow)
  86. t.Cleanup(func() {
  87. testutil.CleanTableByField(bootstrapCtx, conn, "`sys_user_perm`", "userId", userId)
  88. testutil.CleanTable(bootstrapCtx, conn, "`sys_product_member`", mId)
  89. testutil.CleanTable(bootstrapCtx, conn, "`sys_user`", userId)
  90. testutil.CleanTable(bootstrapCtx, conn, "`sys_perm`", permId)
  91. })
  92. adminCtx := ctxhelper.AdminCtx("test_product")
  93. resp, err := NewGetUserPermsLogic(adminCtx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: userId})
  94. require.NoError(t, err)
  95. require.NotNil(t, resp)
  96. assert.Len(t, resp.Perms, 1)
  97. assert.Equal(t, permId, resp.Perms[0].PermId)
  98. }
  99. // TC-1260: 产品 ADMIN 查同级 ADMIN 被拒绝(permsLevel 等级相同时 CheckManageAccess 拒绝)
  100. func TestGetUserPerms_AdminQueriesSameLevelAdmin_Forbidden(t *testing.T) {
  101. bootstrapCtx := ctxhelper.SuperAdminCtx()
  102. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  103. conn := testutil.GetTestSqlConn()
  104. // 目标:ADMIN 类型成员
  105. targetUsername := testutil.UniqueId()
  106. targetUserId := insertTestUser(t, bootstrapCtx, targetUsername, testutil.HashPassword("pass"))
  107. mId := insertTestMemberWithType(t, svcCtx, "test_product", targetUserId, consts.MemberTypeAdmin)
  108. t.Cleanup(func() {
  109. testutil.CleanTable(bootstrapCtx, conn, "`sys_product_member`", mId)
  110. testutil.CleanTable(bootstrapCtx, conn, "`sys_user`", targetUserId)
  111. })
  112. // AdminCtx UserId=2,无任何角色 → callerNoRole=true → CheckManageAccess 拒绝(等级不低于目标)
  113. adminCtx := ctxhelper.AdminCtx("test_product")
  114. _, err := NewGetUserPermsLogic(adminCtx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: targetUserId})
  115. require.Error(t, err)
  116. var ce *response.CodeError
  117. require.True(t, errors.As(err, &ce))
  118. assert.Equal(t, 403, ce.Code())
  119. }
  120. // TC-1261: 普通 MEMBER 查他人被拒绝(RequireProductAdminFor 前置拦截)
  121. func TestGetUserPerms_MemberQueriesOther_Forbidden(t *testing.T) {
  122. bootstrapCtx := ctxhelper.SuperAdminCtx()
  123. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  124. conn := testutil.GetTestSqlConn()
  125. otherUsername := testutil.UniqueId()
  126. otherUserId := insertTestUser(t, bootstrapCtx, otherUsername, testutil.HashPassword("pass"))
  127. mId := insertTestMember(t, svcCtx, "test_product", otherUserId)
  128. t.Cleanup(func() {
  129. testutil.CleanTable(bootstrapCtx, conn, "`sys_product_member`", mId)
  130. testutil.CleanTable(bootstrapCtx, conn, "`sys_user`", otherUserId)
  131. })
  132. memberCtx := ctxhelper.MemberCtx("test_product")
  133. _, err := NewGetUserPermsLogic(memberCtx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: otherUserId})
  134. require.Error(t, err)
  135. var ce *response.CodeError
  136. require.True(t, errors.As(err, &ce))
  137. assert.Equal(t, 403, ce.Code())
  138. assert.Contains(t, ce.Error(), "仅超级管理员或该产品的管理员可执行此操作")
  139. }
  140. // TC-1262: 非 ADMIN 查不存在的 userId 必须 403(RequireProductAdminFor 先于实体读取,消除枚举 oracle)
  141. func TestGetUserPerms_NonAdmin_NonExistentUser_Returns403(t *testing.T) {
  142. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  143. memberCtx := ctxhelper.MemberCtx("test_product")
  144. _, err := NewGetUserPermsLogic(memberCtx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: 999999999})
  145. require.Error(t, err)
  146. var ce *response.CodeError
  147. require.True(t, errors.As(err, &ce))
  148. assert.Equal(t, 403, ce.Code(), "必须是 403 而非 404,防止枚举 userId 存在性")
  149. }
  150. // TC-1263: ADMIN 查不是当前产品成员的用户被拒绝
  151. func TestGetUserPerms_AdminQueriesNonMember_Forbidden(t *testing.T) {
  152. bootstrapCtx := ctxhelper.SuperAdminCtx()
  153. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  154. conn := testutil.GetTestSqlConn()
  155. // 创建用户,但不加入 test_product
  156. username := testutil.UniqueId()
  157. userId := insertTestUser(t, bootstrapCtx, username, testutil.HashPassword("pass"))
  158. t.Cleanup(func() {
  159. testutil.CleanTable(bootstrapCtx, conn, "`sys_user`", userId)
  160. })
  161. adminCtx := ctxhelper.AdminCtx("test_product")
  162. _, err := NewGetUserPermsLogic(adminCtx, svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: userId})
  163. require.Error(t, err)
  164. var ce *response.CodeError
  165. require.True(t, errors.As(err, &ce))
  166. assert.Equal(t, 403, ce.Code())
  167. }
  168. // TC-1264: nil UserDetails(模拟无 JWT)返回 401
  169. func TestGetUserPerms_NoAuth_Returns401(t *testing.T) {
  170. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  171. _, err := NewGetUserPermsLogic(ctxhelper.CustomCtx(nil), svcCtx).GetUserPerms(&types.GetUserPermsReq{UserId: 1})
  172. require.Error(t, err)
  173. var ce *response.CodeError
  174. require.True(t, errors.As(err, &ce))
  175. assert.Equal(t, 401, ce.Code())
  176. }