package auth import ( "context" "fmt" "os" "testing" "time" "github.com/veypi/vbase/cfg" "github.com/veypi/vbase/models" ) // setupTestDB 初始化测试数据库 func setupTestDB() { // 使用 SQLite 内存模式 cfg.Config.DB = "sqlite" cfg.Config.DSN = fmt.Sprintf("file::memory:?cache=shared&_time=%d", time.Now().UnixNano()) // 初始化数据库表 if err := models.AllModels.AutoMigrate(cfg.DB()); err != nil { panic(err) } } // TestMain 负责测试环境的全局初始化 func TestMain(m *testing.M) { setupTestDB() code := m.Run() os.Exit(code) } func getTestAuth() Auth { // 每次获取一个新的实例名,避免测试间冲突(虽然内存库是共享的,但数据清理可能不完全) // 为了简单起见,我们在 TestMain 中只初始化一次 DB,但可以通过应用名区分 appKey := fmt.Sprintf("test_app_%d", time.Now().UnixNano()) a := Factory.New(appKey, models.AppConfig{ Name: "Test App", DefaultRoles: []models.RoleDefinition{ { Code: "admin", Name: "Administrator", Policies: []string{"*:*"}, }, { Code: "editor", Name: "Editor", Policies: []string{ "article:create", "article:read", "article:update", }, }, { Code: "viewer", Name: "Viewer", Policies: []string{ "article:read", }, }, { Code: "deleter", Name: "Deleter", Policies: []string{ "article:delete", }, }, }, }) // 初始化 if err := a.(*appAuth).init(); err != nil { panic(err) } return a } // TestBasicPermission 测试基础权限授予与检查 func TestBasicPermission(t *testing.T) { a := getTestAuth() ctx := context.Background() userID := "user_basic_001" // 初始状态应该无权限 ok, err := a.CheckPermission(ctx, userID, "", "article:read", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no permission initially") } // 授予 viewer 角色 if err := a.GrantRole(ctx, userID, "", "viewer"); err != nil { t.Fatalf("GrantRole failed: %v", err) } // 应该有 article:read 权限 ok, err = a.CheckPermission(ctx, userID, "", "article:read", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if !ok { t.Error("Expected article:read permission after granting viewer role") } // 不应该有 article:create 权限 ok, err = a.CheckPermission(ctx, userID, "", "article:create", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no article:create permission for viewer") } } // TestWildcardPermission 测试通配符权限 func TestWildcardPermission(t *testing.T) { a := getTestAuth() ctx := context.Background() userID := "user_admin_001" // 授予 admin 角色 (*:*) if err := a.GrantRole(ctx, userID, "", "admin"); err != nil { t.Fatalf("GrantRole failed: %v", err) } // 应该拥有所有权限 tests := []string{ "article:read", "article:delete", "user:create", "config:update", // system:config:update 会被解析为 system 应用的权限,而 admin 是 test_app 的 admin } for _, perm := range tests { ok, err := a.CheckPermission(ctx, userID, "", perm, "") if err != nil { t.Errorf("CheckPermission %s failed: %v", perm, err) continue } if !ok { t.Errorf("Expected permission %s for admin", perm) } } } // TestStrictPermissionIsolation 验证权限严格隔离性 (用户请求场景) // 验证:拥有 delete 权限的用户,是否能通过 read 权限检查 func TestStrictPermissionIsolation(t *testing.T) { a := getTestAuth() ctx := context.Background() userID := "user_deleter_001" // 授予 deleter 角色 (只包含 article:delete) if err := a.GrantRole(ctx, userID, "", "deleter"); err != nil { t.Fatalf("GrantRole failed: %v", err) } // 1. 检查 article:delete (应该通过) ok, err := a.CheckPermission(ctx, userID, "", "article:delete", "") if err != nil { t.Fatalf("CheckPermission error: %v", err) } if !ok { t.Errorf("Expected user to have article:delete permission") } // 2. 检查 article:read (应该失败) // 关键验证点:delete 不包含 read ok, err = a.CheckPermission(ctx, userID, "", "article:read", "") if err != nil { t.Fatalf("CheckPermission error: %v", err) } if ok { t.Errorf("Strict isolation failed: User with 'article:delete' passed 'article:read' check") } } // TestOrgIsolation 测试多租户/组织隔离 func TestOrgIsolation(t *testing.T) { a := getTestAuth() ctx := context.Background() userID := "user_org_001" orgA := "org_a" orgB := "org_b" // 在 OrgA 中授予 editor 角色 if err := a.GrantRole(ctx, userID, orgA, "editor"); err != nil { t.Fatalf("GrantRole failed: %v", err) } // 在 OrgA 上下文中检查 article:create (应该通过) ok, err := a.CheckPermission(ctx, userID, orgA, "article:create", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if !ok { t.Error("Expected permission in OrgA") } // 在 OrgB 上下文中检查 article:create (应该失败) ok, err = a.CheckPermission(ctx, userID, orgB, "article:create", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no permission in OrgB (role was granted in OrgA)") } // 在全局上下文中检查 (应该失败,因为角色绑定在 OrgA) ok, err = a.CheckPermission(ctx, userID, "", "article:create", "") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no global permission") } } // TestResourcePermission 测试特定资源权限 func TestResourcePermission(t *testing.T) { a := getTestAuth() ctx := context.Background() userID := "user_res_001" resID := "doc_123" // 需要先创建权限定义,因为 GrantResourcePerm 会检查权限是否存在 permID := fmt.Sprintf("%s:doc:read", a.(*appAuth).appKey) perm := models.Permission{ ID: permID, AppKey: a.(*appAuth).appKey, Resource: "doc", Action: "read", Description: "Read Doc", } if err := cfg.DB().Create(&perm).Error; err != nil { t.Fatalf("Failed to create permission: %v", err) } // 初始无权限 ok, err := a.CheckPermission(ctx, userID, "", "doc:read", resID) if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no permission") } // 授予对特定资源 doc_123 的 doc:read 权限 if err := a.GrantResourcePerm(ctx, userID, "", "doc:read", resID); err != nil { t.Fatalf("GrantResourcePerm failed: %v", err) } // 检查 doc:read on doc_123 (应该通过) ok, err = a.CheckPermission(ctx, userID, "", "doc:read", resID) if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if !ok { t.Error("Expected permission on specific resource") } // 检查 doc:read on doc_456 (应该失败) ok, err = a.CheckPermission(ctx, userID, "", "doc:read", "doc_456") if err != nil { t.Fatalf("CheckPermission failed: %v", err) } if ok { t.Error("Expected no permission on other resource") } }