diff --git a/backend/services/accountgroup/service.go b/backend/services/accountgroup/service.go index e9ead17..b4d9158 100644 --- a/backend/services/accountgroup/service.go +++ b/backend/services/accountgroup/service.go @@ -21,14 +21,15 @@ var ( // ScopePredicate 的外层必须是用户表。使用实时子查询,不缓存管理员的分组范围。 // 未建立成员关系的旧账号以及新账号都属于默认分组,无需迁移或复制账号数据。 func ScopePredicate(actorID int) (string, []any) { - return `(id IN ( + return `((id IN ( SELECT gm.user_id FROM account_group_member gm JOIN account_group_member am ON gm.group_id = am.group_id WHERE am.user_id = ? ) OR ((id NOT IN (SELECT user_id FROM account_group_member) OR id IN (SELECT user_id FROM account_group_member WHERE group_id = 0)) AND (NOT EXISTS (SELECT 1 FROM account_group_member WHERE user_id = ?) - OR EXISTS (SELECT 1 FROM account_group_member WHERE user_id = ? AND group_id = 0))))`, + OR EXISTS (SELECT 1 FROM account_group_member WHERE user_id = ? AND group_id = 0)))) + AND NOT ` + models.SuperAdminPredicate + `)`, []any{actorID, actorID, actorID} } diff --git a/backend/services/accountgroup/service_test.go b/backend/services/accountgroup/service_test.go new file mode 100644 index 0000000..a7b43bf --- /dev/null +++ b/backend/services/accountgroup/service_test.go @@ -0,0 +1,43 @@ +package accountgroup + +import ( + "testing" + + "git.pcux.cn/xuans/Smail/models" + "git.pcux.cn/xuans/Smail/services/access" + _ "modernc.org/sqlite" + "xorm.io/xorm" +) + +func TestCanAccessExcludesSuperAdminFromAdminScope(t *testing.T) { + engine, err := xorm.NewEngine("sqlite", ":memory:") + if err != nil { + t.Fatal(err) + } + defer engine.Close() + + if err := engine.Sync2(new(models.User), new(models.AccountGroupMember)); err != nil { + t.Fatal(err) + } + + superAdmin := models.User{Account: "superadmin", Name: "超级管理员", Role: string(access.RoleSuperAdmin)} + admin := models.User{Account: "admin", Name: "分组管理员", Role: string(access.RoleAdmin), IsAdmin: 1} + member := models.User{Account: "member", Name: "普通用户", Role: string(access.RoleUser)} + if _, err := engine.Insert(&superAdmin, &admin, &member); err != nil { + t.Fatal(err) + } + + if _, err := engine.Insert( + &models.AccountGroupMember{UserID: admin.ID, GroupID: 1}, + &models.AccountGroupMember{UserID: member.ID, GroupID: 1}, + ); err != nil { + t.Fatal(err) + } + + if CanAccess(engine, admin.ID, access.RoleAdmin, superAdmin.ID) { + t.Fatal("管理员不应访问超级管理员账户") + } + if !CanAccess(engine, admin.ID, access.RoleAdmin, member.ID) { + t.Fatal("管理员应访问同组普通用户账户") + } +}