// Package router 装配 gin 引擎与各模块路由。 // 路由分层:/api/ma(小程序,靠请求头 app_id 鉴权)、/api/admin(后台)。 package router import ( "context" "log/slog" "os" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" adminhdl "portal-mini-go/internal/handler/admin" miniapphdl "portal-mini-go/internal/handler/admin/miniapp" rbachdl "portal-mini-go/internal/handler/admin/rbac" userhdl "portal-mini-go/internal/handler/admin/user" app1hdl "portal-mini-go/internal/handler/miniapp/app1" "portal-mini-go/internal/middleware" "portal-mini-go/internal/pkg/config" "portal-mini-go/internal/pkg/response" "portal-mini-go/internal/pkg/session" "portal-mini-go/internal/pkg/wechat" adminrepo "portal-mini-go/internal/repository/admin" miniapprepo "portal-mini-go/internal/repository/miniapp" "portal-mini-go/internal/repository/user" authsvc "portal-mini-go/internal/service/admin/auth" miniappsvc "portal-mini-go/internal/service/admin/miniapp" adminrbac "portal-mini-go/internal/service/admin/rbac" usersvc "portal-mini-go/internal/service/admin/user" app1svc "portal-mini-go/internal/service/miniapp/app1" ) // New 构造并装配整个 HTTP 服务。 func New(cfg *config.Config, db *gorm.DB, store session.Store) *gin.Engine { if cfg.Server.Mode == "release" { gin.SetMode(gin.ReleaseMode) } r := gin.New() r.Use(middleware.Recovery(), middleware.Trace(), middleware.ErrorHandler()) r.GET("/healthz", func(c *gin.Context) { response.OK(c, gin.H{"status": "ok"}) }) // 共享基础设施:微信客户端、用户仓储、小程序仓储。 wx := wechat.NewClient() userRepo := user.New(db) miniRepo := miniapprepo.New(db) // 小程序分组:先校验请求头 app_id 身份,再挂载各小程序业务路由。 ma := r.Group("/api/ma") ma.Use(middleware.MiniAppAuth(miniRepo)) { app1Svc := app1svc.New(userRepo, miniRepo, wx, store) app1hdl.Register(ma, app1hdl.NewHandler(app1Svc), middleware.MiniUserAuth(store)) } // 后台 RBAC 基础设施:仓储、缓存、权限 Provider、种子初始化。 adminUserRepo := adminrepo.NewUserRepository(db) adminRoleRepo := adminrepo.NewRoleRepository(db) adminPermRepo := adminrepo.NewPermissionRepository(db) permCache := adminrbac.NewMemoryCache(5 * time.Minute) provider := adminrbac.NewProvider(adminUserRepo, adminRoleRepo, adminPermRepo, permCache) if err := provider.Seed(context.Background(), seedDefault("ADMIN_SEED_USERNAME", "admin"), seedDefault("ADMIN_SEED_PASSWORD", "Admin@123456"), ); err != nil { slog.Error("rbac seed", slog.Any("err", err)) } // 后台管理:登录为公开接口,其余均经 JWT 鉴权 + 权限加载(注入角色/权限集到 context)。 ad := r.Group("/api/admin") { authSvc := authsvc.New(adminUserRepo, provider, cfg.Admin.JWTSecret, parseTTL(cfg.Admin.TokenTTL)) adminHandler := adminhdl.NewHandler(authSvc) // 登录公开,不挂 JWT 鉴权中间件。 adminhdl.RegisterLogin(ad, adminHandler) // 鉴权后分组:AdminAuth + PermissionLoader。 authAd := ad.Group("") authAd.Use(middleware.AdminAuth(cfg.Admin.JWTSecret)) authAd.Use(middleware.PermissionLoader(provider)) { adminhdl.Register(authAd, adminHandler) // RBAC 管理接口(自身受 PermAdminManage / PermRoleManage / PermPermManage 守卫)。 rbacHandler := rbachdl.NewHandler( adminrbac.NewAdminService(adminUserRepo, provider), adminrbac.NewRoleService(adminRoleRepo, provider), adminrbac.NewPermissionService(adminPermRepo, provider), ) rbachdl.Register(authAd, rbacHandler) // 小程序管理:被后台纳管的微信小程序配置(增删改查)。 miniSvc := miniappsvc.New(miniRepo) miniapphdl.Register(authAd, miniapphdl.NewHandler(miniSvc)) // 用户管理:各小程序端用户(列表、详情、编辑、禁用/启用)。 userSvc := usersvc.New(userRepo) userhdl.Register(authAd, userhdl.NewHandler(userSvc)) } } return r } // seedDefault 读取环境变量,缺失时回退到默认值(仅用于首次种子初始化)。 func seedDefault(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def } func parseTTL(s string) time.Duration { if d, err := time.ParseDuration(s); err == nil { return d } return 24 * time.Hour }