You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

206 lines
4.7 KiB

// 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/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
}
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{})
if err != nil {
panic("Failed to migrate database: " + err.Error())
}
// 初始化 Casbin
enforcer := initCasbin(db)
// 种子超级管理员
seedSuperAdmin(db)
// 种子 Casbin 策略
seedCasbinPolicies(enforcer)
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,
}
}
// 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"},
}
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")
}