// Code scaffolded by goctl. Safe to edit. // goctl 1.9.2 package svc import ( "context" "crypto/md5" "fmt" "log" "github.com/casbin/casbin/v2" casbinmodel "github.com/casbin/casbin/v2/model" gormadapter "github.com/casbin/gorm-adapter/v3" "github.com/youruser/base/internal/config" "github.com/youruser/base/internal/middleware" "github.com/youruser/base/internal/storage" "github.com/youruser/base/model" "gorm.io/driver/mysql" "gorm.io/gorm" "github.com/zeromicro/go-zero/rest" ) const casbinModelText = ` [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 = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && r.act == p.act ` type ServiceContext struct { Config config.Config Cors rest.Middleware Log rest.Middleware Auth rest.Middleware Authz rest.Middleware // 数据库连接 DB *gorm.DB // Casbin enforcer Enforcer *casbin.Enforcer // 文件存储 Storage storage.Storage } func NewServiceContext(c config.Config) *ServiceContext { // 创建数据库连接 dsn := c.MySQL.DSN db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("Failed to connect database: " + err.Error()) } // 自动迁移表 err = db.AutoMigrate( &model.User{}, &model.Profile{}, &model.File{}, &model.Menu{}, &model.Role{}, &model.RoleMenu{}, &model.Organization{}, &model.UserOrganization{}, // AI models &model.AIProvider{}, &model.AIModel{}, &model.AIApiKey{}, &model.AIConversation{}, &model.AIChatMessage{}, &model.AIUsageRecord{}, &model.AIUserQuota{}, ) if err != nil { panic("Failed to migrate database: " + err.Error()) } // 初始化 Casbin enforcer := initCasbin(db) // 种子超级管理员 seedSuperAdmin(db) // 种子 Casbin 策略 seedCasbinPolicies(enforcer) // 种子角色、菜单、角色-菜单关联 seedRoles(db) seedMenus(db) seedRoleMenus(db) // 初始化存储 store, err := storage.NewStorage(c.Storage) if err != nil { panic("Failed to initialize storage: " + err.Error()) } log.Printf("[Storage] Initialized with type: %s", c.Storage.Type) return &ServiceContext{ Config: c, Cors: middleware.NewCorsMiddleware().Handle, Log: middleware.NewLogMiddleware().Handle, Auth: middleware.NewAuthMiddleware().Handle, Authz: middleware.NewAuthzMiddleware(enforcer).Handle, DB: db, Enforcer: enforcer, Storage: store, } } // Close 关闭资源 func (s *ServiceContext) Close() error { if s.DB != nil { sqlDB, err := s.DB.DB() if err != nil { return err } return sqlDB.Close() } return nil } // initCasbin 初始化 Casbin enforcer func initCasbin(db *gorm.DB) *casbin.Enforcer { // 使用 GORM adapter(自动创建 casbin_rule 表) adapter, err := gormadapter.NewAdapterByDB(db) if err != nil { panic("Failed to create Casbin adapter: " + err.Error()) } // 从字符串加载 model m, err := casbinmodel.NewModelFromString(casbinModelText) if err != nil { panic("Failed to create Casbin model: " + err.Error()) } enforcer, err := casbin.NewEnforcer(m, adapter) if err != nil { panic("Failed to create Casbin enforcer: " + err.Error()) } // 加载策略 if err := enforcer.LoadPolicy(); err != nil { panic("Failed to load Casbin policy: " + err.Error()) } log.Println("[Casbin] Enforcer initialized successfully") return enforcer } // seedSuperAdmin 首次启动创建超级管理员 func seedSuperAdmin(db *gorm.DB) { ctx := context.Background() existing, err := model.FindOneByUsername(ctx, db, "admin") if err == nil { if existing.Role != model.RoleSuperAdmin { existing.Role = model.RoleSuperAdmin existing.Source = model.SourceSystem model.Update(ctx, db, existing) log.Println("[Seed] Updated admin to super_admin role") } return } password := fmt.Sprintf("%x", md5.Sum([]byte("admin123"))) admin := &model.User{ Username: "admin", Phone: "13800000000", Email: "", Password: password, Role: model.RoleSuperAdmin, Source: model.SourceSystem, Remark: "系统自动创建的超级管理员", Status: 1, } _, err = model.Insert(ctx, db, admin) if err != nil { log.Printf("[Seed] Failed to create super admin: %v", err) return } log.Println("[Seed] Super admin created: admin / admin123") } // seedCasbinPolicies 种子 Casbin 策略(幂等) func seedCasbinPolicies(enforcer *casbin.Enforcer) { // 角色层级: super_admin > admin > user > guest roleHierarchy := [][]string{ {"super_admin", "admin"}, {"admin", "user"}, {"user", "guest"}, } for _, g := range roleHierarchy { if has, _ := enforcer.HasGroupingPolicy(g[0], g[1]); !has { enforcer.AddGroupingPolicy(g[0], g[1]) } } // 默认策略 policies := [][]string{ // guest: 仪表盘只读 {"guest", "/api/v1/dashboard/*", "GET"}, // user: 个人中心 {"user", "/api/v1/profile/*", "GET"}, {"user", "/api/v1/profile/*", "PUT"}, {"user", "/api/v1/profile/*", "POST"}, // admin: 用户管理(增查改) {"admin", "/api/v1/users", "GET"}, {"admin", "/api/v1/user", "POST"}, {"admin", "/api/v1/user/:id", "GET"}, {"admin", "/api/v1/user/:id", "PUT"}, // super_admin: 用户删除 {"super_admin", "/api/v1/user/:id", "DELETE"}, // user: 文件管理 {"user", "/api/v1/file/upload", "POST"}, {"user", "/api/v1/files", "GET"}, {"user", "/api/v1/file/:id", "GET"}, {"user", "/api/v1/file/:id/url", "GET"}, {"user", "/api/v1/file/:id", "PUT"}, // super_admin: 文件删除 {"super_admin", "/api/v1/file/:id", "DELETE"}, // user: 个人机构相关 {"user", "/api/v1/profile/orgs", "GET"}, {"user", "/api/v1/profile/current-org", "PUT"}, // admin: 菜单管理(读取) {"admin", "/api/v1/menus", "GET"}, // super_admin: 菜单管理(增删改) {"super_admin", "/api/v1/menu", "POST"}, {"super_admin", "/api/v1/menu/:id", "PUT"}, {"super_admin", "/api/v1/menu/:id", "DELETE"}, // admin: 角色管理(读取) {"admin", "/api/v1/roles", "GET"}, {"admin", "/api/v1/role/:id/menus", "GET"}, // super_admin: 角色管理(增删改) {"super_admin", "/api/v1/role", "POST"}, {"super_admin", "/api/v1/role/:id", "PUT"}, {"super_admin", "/api/v1/role/:id", "DELETE"}, {"super_admin", "/api/v1/role/:id/menus", "PUT"}, // admin: 机构管理 {"admin", "/api/v1/organizations", "GET"}, {"admin", "/api/v1/organization", "POST"}, {"admin", "/api/v1/organization/:id", "PUT"}, {"admin", "/api/v1/organization/:id/members", "GET"}, {"admin", "/api/v1/organization/:id/member", "POST"}, {"admin", "/api/v1/organization/:id/member/:userId", "PUT"}, {"admin", "/api/v1/organization/:id/member/:userId", "DELETE"}, // super_admin: 机构删除 {"super_admin", "/api/v1/organization/:id", "DELETE"}, } for _, p := range policies { if has, _ := enforcer.HasPolicy(p[0], p[1], p[2]); !has { enforcer.AddPolicy(p[0], p[1], p[2]) } } enforcer.SavePolicy() log.Println("[Casbin] Policies seeded successfully") } // seedRoles 种子系统角色(幂等) func seedRoles(db *gorm.DB) { roles := []model.Role{ {Name: "超级管理员", Code: model.RoleSuperAdmin, Description: "系统超级管理员", IsSystem: true, SortOrder: 1, Status: 1}, {Name: "管理员", Code: model.RoleAdmin, Description: "系统管理员", IsSystem: true, SortOrder: 2, Status: 1}, {Name: "普通用户", Code: model.RoleUser, Description: "普通用户", IsSystem: true, SortOrder: 3, Status: 1}, {Name: "访客", Code: model.RoleGuest, Description: "访客", IsSystem: true, SortOrder: 4, Status: 1}, } for _, r := range roles { var existing model.Role if err := db.Where("code = ?", r.Code).First(&existing).Error; err != nil { db.Create(&r) } } log.Println("[Seed] Roles seeded successfully") } // seedMenus 种子默认菜单(幂等) func seedMenus(db *gorm.DB) { menus := []model.Menu{ {Name: "我的", Path: "/my", Icon: "User", Type: "default", SortOrder: 1, Visible: true, Status: 1}, {Name: "仪表盘", Path: "/dashboard", Icon: "LayoutDashboard", Type: "config", SortOrder: 2, Visible: true, Status: 1}, {Name: "用户管理", Path: "/users", Icon: "Users", Type: "config", SortOrder: 3, Visible: true, Status: 1}, {Name: "文件管理", Path: "/files", Icon: "FolderOpen", Type: "config", SortOrder: 4, Visible: true, Status: 1}, {Name: "角色管理", Path: "/roles", Icon: "Shield", Type: "config", SortOrder: 5, Visible: true, Status: 1}, {Name: "菜单管理", Path: "/menus", Icon: "Menu", Type: "config", SortOrder: 6, Visible: true, Status: 1}, {Name: "机构管理", Path: "/organizations", Icon: "Building2", Type: "config", SortOrder: 7, Visible: true, Status: 1}, {Name: "设置", Path: "/settings", Icon: "Settings", Type: "default", SortOrder: 8, Visible: true, Status: 1}, } for _, m := range menus { var existing model.Menu if err := db.Where("path = ?", m.Path).First(&existing).Error; err != nil { db.Create(&m) } } log.Println("[Seed] Menus seeded successfully") } // seedRoleMenus 种子角色-菜单关联(幂等) func seedRoleMenus(db *gorm.DB) { // 获取所有角色 var roles []model.Role db.Find(&roles) // 获取所有菜单 var menus []model.Menu db.Find(&menus) if len(roles) == 0 || len(menus) == 0 { return } // 构建菜单分类 var allMenuIds []int64 var defaultMenuIds []int64 for _, m := range menus { allMenuIds = append(allMenuIds, m.Id) if m.Type == "default" { defaultMenuIds = append(defaultMenuIds, m.Id) } } for _, r := range roles { // 检查角色是否已有菜单关联 var count int64 db.Model(&model.RoleMenu{}).Where("role_id = ?", r.Id).Count(&count) if count > 0 { continue } var menuIds []int64 switch r.Code { case model.RoleSuperAdmin, model.RoleAdmin: menuIds = allMenuIds case model.RoleUser, model.RoleGuest: menuIds = defaultMenuIds } if len(menuIds) > 0 { records := make([]model.RoleMenu, 0, len(menuIds)) for _, menuId := range menuIds { records = append(records, model.RoleMenu{RoleId: r.Id, MenuId: menuId}) } db.Create(&records) } } log.Println("[Seed] RoleMenus seeded successfully") }