package service import ( "context" "testing" withmodel "with_you/internal/model" "github.com/casbin/casbin/v3" casbinmodel "github.com/casbin/casbin/v3/model" ) // newTestEnforcer 构造一个内存 Enforcer,加载与生产相同的 model.conf 语义(globMatch), // 并按 seedPermissions 的约定注入角色策略,便于在不依赖 DB 的情况下验证 matcher 行为。 func newTestEnforcer(t *testing.T) *casbin.Enforcer { t.Helper() // 与 configs/casbin/model.conf 保持一致;用 globMatch 而非 keyMatch2。 mText := ` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub == p.sub && globMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") ` m, err := casbinmodel.NewModelFromString(mText) if err != nil { t.Fatalf("parse model: %v", err) } e, err := casbin.NewEnforcer(m) if err != nil { t.Fatalf("new enforcer: %v", err) } // 与 seedPermissions 一致:super_admin=admin.** 通配,admin 业务能力, // moderator 内容审核。admin.logs.export 仅 super_admin 拥有(admin 只有 admin.logs read)。 policies := [][]string{ {withmodel.RoleSuperAdmin, "admin/**", "*"}, {withmodel.RoleAdmin, "admin/users", "read"}, {withmodel.RoleAdmin, "admin/users/status", "write"}, {withmodel.RoleAdmin, "admin/users/devices", "read"}, {withmodel.RoleAdmin, "admin/posts", "*"}, {withmodel.RoleAdmin, "admin/comments", "*"}, {withmodel.RoleAdmin, "admin/groups", "*"}, {withmodel.RoleAdmin, "admin/channels", "*"}, {withmodel.RoleAdmin, "admin/dashboard", "read"}, {withmodel.RoleAdmin, "admin/reports", "*"}, {withmodel.RoleAdmin, "admin/verifications", "*"}, {withmodel.RoleAdmin, "admin/profile_audits", "*"}, {withmodel.RoleAdmin, "admin/materials", "*"}, {withmodel.RoleAdmin, "admin/logs", "read"}, {withmodel.RoleModerator, "admin/posts", "read"}, {withmodel.RoleModerator, "admin/posts", "write"}, {withmodel.RoleModerator, "admin/comments", "read"}, {withmodel.RoleModerator, "admin/comments", "write"}, {withmodel.RoleModerator, "admin/reports", "read"}, {withmodel.RoleModerator, "admin/reports", "write"}, } for _, p := range policies { if _, err := e.AddPolicy(p[0], p[1], p[2]); err != nil { t.Fatalf("add policy %v: %v", p, err) } } return e } // mustAllow / mustDeny 简化断言。 func mustAllow(t *testing.T, e *casbin.Enforcer, sub, obj, act string) { t.Helper() ok, err := e.Enforce(sub, obj, act) if err != nil { t.Fatalf("Enforce(%s,%s,%s) err: %v", sub, obj, act, err) } if !ok { t.Errorf("Enforce(%s,%s,%s) = false, want true", sub, obj, act) } } func mustDeny(t *testing.T, e *casbin.Enforcer, sub, obj, act string) { t.Helper() ok, err := e.Enforce(sub, obj, act) if err != nil { t.Fatalf("Enforce(%s,%s,%s) err: %v", sub, obj, act, err) } if ok { t.Errorf("Enforce(%s,%s,%s) = true, want false", sub, obj, act) } } // TestSuperAdminWildcard 通配多级资源(globMatch ** 跨 '.')。 func TestSuperAdminWildcard(t *testing.T) { e := newTestEnforcer(t) mustAllow(t, e, withmodel.RoleSuperAdmin, "admin/users/roles/write", "write") mustAllow(t, e, withmodel.RoleSuperAdmin, "admin/logs/export", "read") mustAllow(t, e, withmodel.RoleSuperAdmin, "admin/dashboard", "read") } // TestAdminBusinessCapabilities admin 拥有的业务能力放行。 func TestAdminBusinessCapabilities(t *testing.T) { e := newTestEnforcer(t) mustAllow(t, e, withmodel.RoleAdmin, "admin/posts", "write") mustAllow(t, e, withmodel.RoleAdmin, "admin/posts", "read") mustAllow(t, e, withmodel.RoleAdmin, "admin/users", "read") mustAllow(t, e, withmodel.RoleAdmin, "admin/logs", "read") } // TestAdminCannotReachSuperAdminOnlyResources admin 不能触及 super_admin 独占资源。 // - admin.logs.export 仅 super_admin 拥有,admin 应被拒。 // - admin.users.roles.write 仅 super_admin 拥有。 // - admin.roles.* 仅 super_admin 拥有。 func TestAdminCannotReachSuperAdminOnlyResources(t *testing.T) { e := newTestEnforcer(t) mustDeny(t, e, withmodel.RoleAdmin, "admin/logs/export", "read") mustDeny(t, e, withmodel.RoleAdmin, "admin/users/roles", "write") mustDeny(t, e, withmodel.RoleAdmin, "admin/roles", "read") // admin.users.status.write 是 admin 自己的能力,确认不受影响。 mustAllow(t, e, withmodel.RoleAdmin, "admin/users/status", "write") } // TestModeratorContentModeration moderator 仅内容审核。 func TestModeratorContentModeration(t *testing.T) { e := newTestEnforcer(t) mustAllow(t, e, withmodel.RoleModerator, "admin/posts", "read") mustAllow(t, e, withmodel.RoleModerator, "admin/comments", "write") mustAllow(t, e, withmodel.RoleModerator, "admin/reports", "write") // moderator 不应触及用户管理。 mustDeny(t, e, withmodel.RoleModerator, "admin/users", "read") mustDeny(t, e, withmodel.RoleModerator, "admin/logs", "read") } // TestWildcardDoesNotCrossBoundaryWithSingleStar 校验 admin/* 在 globMatch 下不跨 '/'。 // 此用例用于防止未来有人误把 super_admin 通配写回 admin/*(单层),导致 super_admin 实际拿不到 // admin/users/roles/write 这类多级资源的能力(应使用 admin/**)。 // // 注意:本测试构造独立的 Enforcer,仅注入 admin/* 单层策略,避免 newTestEnforcer 的 // admin/** 策略干扰断言。 func TestWildcardDoesNotCrossBoundaryWithSingleStar(t *testing.T) { mText := ` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub == p.sub && globMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") ` m, err := casbinmodel.NewModelFromString(mText) if err != nil { t.Fatalf("parse model: %v", err) } e, err := casbin.NewEnforcer(m) if err != nil { t.Fatalf("new enforcer: %v", err) } if _, err := e.AddPolicy(withmodel.RoleSuperAdmin, "admin/*", "*"); err != nil { t.Fatalf("add policy: %v", err) } // 单层 * 不跨 '/':admin/* 仅命中 admin/,不能命中 admin/users/roles/write。 mustDeny(t, e, withmodel.RoleSuperAdmin, "admin/users/roles/write", "write") mustAllow(t, e, withmodel.RoleSuperAdmin, "admin/posts", "write") } // TestEnforceForUser_NoRolesNoPanic 用户无角色时 EnforceForUser 走默认 user 角色。 func TestEnforceForUser_NoRolesNoPanic(t *testing.T) { e := newTestEnforcer(t) // user 角色无任何 admin 策略,应全部拒绝。 mustDeny(t, e, "user", "admin/posts", "read") // 防止 lint 抱怨未使用 context。 _ = context.Background() }