package router import ( "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" "github.com/swaggo/gin-swagger" "github.com/user-management-system/internal/api/handler" "github.com/user-management-system/internal/api/middleware" ) type Router struct { engine *gin.Engine authHandler *handler.AuthHandler userHandler *handler.UserHandler roleHandler *handler.RoleHandler permissionHandler *handler.PermissionHandler deviceHandler *handler.DeviceHandler logHandler *handler.LogHandler passwordResetHandler *handler.PasswordResetHandler captchaHandler *handler.CaptchaHandler totpHandler *handler.TOTPHandler webhookHandler *handler.WebhookHandler exportHandler *handler.ExportHandler statsHandler *handler.StatsHandler smsHandler *handler.SMSHandler avatarHandler *handler.AvatarHandler customFieldHandler *handler.CustomFieldHandler themeHandler *handler.ThemeHandler authMiddleware *middleware.AuthMiddleware rateLimitMiddleware *middleware.RateLimitMiddleware opLogMiddleware *middleware.OperationLogMiddleware ipFilterMiddleware *middleware.IPFilterMiddleware ssoHandler *handler.SSOHandler } func NewRouter( authHandler *handler.AuthHandler, userHandler *handler.UserHandler, roleHandler *handler.RoleHandler, permissionHandler *handler.PermissionHandler, deviceHandler *handler.DeviceHandler, logHandler *handler.LogHandler, authMiddleware *middleware.AuthMiddleware, rateLimitMiddleware *middleware.RateLimitMiddleware, opLogMiddleware *middleware.OperationLogMiddleware, passwordResetHandler *handler.PasswordResetHandler, captchaHandler *handler.CaptchaHandler, totpHandler *handler.TOTPHandler, webhookHandler *handler.WebhookHandler, ipFilterMiddleware *middleware.IPFilterMiddleware, exportHandler *handler.ExportHandler, statsHandler *handler.StatsHandler, smsHandler *handler.SMSHandler, customFieldHandler *handler.CustomFieldHandler, themeHandler *handler.ThemeHandler, ssoHandler *handler.SSOHandler, avatarHandler ...*handler.AvatarHandler, ) *Router { engine := gin.New() var avatar *handler.AvatarHandler if len(avatarHandler) > 0 { avatar = avatarHandler[0] } return &Router{ engine: engine, authHandler: authHandler, userHandler: userHandler, roleHandler: roleHandler, permissionHandler: permissionHandler, deviceHandler: deviceHandler, logHandler: logHandler, passwordResetHandler: passwordResetHandler, captchaHandler: captchaHandler, totpHandler: totpHandler, webhookHandler: webhookHandler, exportHandler: exportHandler, statsHandler: statsHandler, smsHandler: smsHandler, customFieldHandler: customFieldHandler, themeHandler: themeHandler, ssoHandler: ssoHandler, avatarHandler: avatar, authMiddleware: authMiddleware, rateLimitMiddleware: rateLimitMiddleware, opLogMiddleware: opLogMiddleware, ipFilterMiddleware: ipFilterMiddleware, } } func (r *Router) Setup() *gin.Engine { r.engine.Use(middleware.Recover()) r.engine.Use(middleware.ErrorHandler()) r.engine.Use(middleware.Logger()) r.engine.Use(middleware.SecurityHeaders()) r.engine.Use(middleware.NoStoreSensitiveResponses()) r.engine.Use(middleware.CORS()) r.engine.Static("/uploads", "./uploads") r.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) if r.ipFilterMiddleware != nil { r.engine.Use(r.ipFilterMiddleware.Filter()) } if r.opLogMiddleware != nil { r.engine.Use(r.opLogMiddleware.Record()) } v1 := r.engine.Group("/api/v1") { authGroup := v1.Group("/auth") { authGroup.POST("/register", r.rateLimitMiddleware.Register(), r.authHandler.Register) authGroup.POST("/bootstrap-admin", r.rateLimitMiddleware.Register(), r.authHandler.BootstrapAdmin) authGroup.POST("/login", r.rateLimitMiddleware.Login(), r.authHandler.Login) authGroup.POST("/refresh", r.rateLimitMiddleware.Refresh(), r.authHandler.RefreshToken) authGroup.GET("/capabilities", r.authHandler.GetAuthCapabilities) authGroup.GET("/activate", r.authHandler.ActivateEmail) authGroup.POST("/resend-activation", r.authHandler.ResendActivationEmail) if r.authHandler.SupportsEmailCodeLogin() { authGroup.POST("/send-email-code", r.rateLimitMiddleware.Register(), r.authHandler.SendEmailCode) authGroup.POST("/login/email-code", r.rateLimitMiddleware.Login(), r.authHandler.LoginByEmailCode) } if r.smsHandler != nil { authGroup.POST("/send-code", r.rateLimitMiddleware.Register(), r.smsHandler.SendCode) authGroup.POST("/login/code", r.rateLimitMiddleware.Login(), r.smsHandler.LoginByCode) } if r.passwordResetHandler != nil { authGroup.POST("/forgot-password", r.passwordResetHandler.ForgotPassword) authGroup.GET("/reset-password", r.passwordResetHandler.ValidateResetToken) authGroup.POST("/reset-password", r.passwordResetHandler.ResetPassword) // 短信密码重置 authGroup.POST("/forgot-password/phone", r.passwordResetHandler.ForgotPasswordByPhone) authGroup.POST("/reset-password/phone", r.passwordResetHandler.ResetPasswordByPhone) } if r.captchaHandler != nil { authGroup.GET("/captcha", r.captchaHandler.GenerateCaptcha) authGroup.GET("/captcha/image", r.captchaHandler.GetCaptchaImage) authGroup.POST("/captcha/verify", r.captchaHandler.VerifyCaptcha) } authGroup.GET("/oauth/providers", r.authHandler.GetEnabledOAuthProviders) authGroup.GET("/oauth/:provider", r.authHandler.OAuthLogin) authGroup.GET("/oauth/:provider/callback", r.authHandler.OAuthCallback) authGroup.POST("/oauth/exchange", r.authHandler.OAuthExchange) } // 公开主题接口(无需认证) if r.themeHandler != nil { themePublic := v1.Group("") { themePublic.GET("/theme/active", r.themeHandler.GetActiveTheme) } } protected := v1.Group("") protected.Use(r.authMiddleware.Required()) protected.Use(r.rateLimitMiddleware.API()) { protected.GET("/auth/csrf-token", r.authHandler.GetCSRFToken) protected.POST("/auth/logout", r.authHandler.Logout) protected.GET("/auth/userinfo", r.authHandler.GetUserInfo) protected.POST("/users/me/bind-email/code", r.authHandler.SendEmailBindCode) protected.POST("/users/me/bind-email", r.authHandler.BindEmail) protected.DELETE("/users/me/bind-email", r.authHandler.UnbindEmail) protected.POST("/users/me/bind-phone/code", r.authHandler.SendPhoneBindCode) protected.POST("/users/me/bind-phone", r.authHandler.BindPhone) protected.DELETE("/users/me/bind-phone", r.authHandler.UnbindPhone) protected.GET("/users/me/social-accounts", r.authHandler.GetSocialAccounts) protected.POST("/users/me/bind-social", r.authHandler.BindSocialAccount) protected.DELETE("/users/me/bind-social/:provider", r.authHandler.UnbindSocialAccount) users := protected.Group("/users") { users.POST("", middleware.RequirePermission("user:manage"), r.userHandler.CreateUser) users.GET("", r.userHandler.ListUsers) users.GET("/:id", r.userHandler.GetUser) users.PUT("/:id", r.userHandler.UpdateUser) users.DELETE("/:id", middleware.RequirePermission("user:delete"), r.userHandler.DeleteUser) users.PUT("/:id/password", r.userHandler.UpdatePassword) users.PUT("/:id/status", middleware.RequirePermission("user:manage"), r.userHandler.UpdateUserStatus) users.GET("/:id/roles", r.userHandler.GetUserRoles) users.PUT("/:id/roles", middleware.RequirePermission("user:manage"), r.userHandler.AssignRoles) if r.avatarHandler != nil { users.POST("/:id/avatar", r.avatarHandler.UploadAvatar) } } roles := protected.Group("/roles") roles.Use(middleware.AdminOnly()) { roles.POST("", r.roleHandler.CreateRole) roles.GET("", r.roleHandler.ListRoles) roles.GET("/:id", r.roleHandler.GetRole) roles.PUT("/:id", r.roleHandler.UpdateRole) roles.DELETE("/:id", r.roleHandler.DeleteRole) roles.PUT("/:id/status", r.roleHandler.UpdateRoleStatus) roles.GET("/:id/permissions", r.roleHandler.GetRolePermissions) roles.PUT("/:id/permissions", r.roleHandler.AssignPermissions) } permissions := protected.Group("/permissions") permissions.Use(middleware.AdminOnly()) { permissions.POST("", r.permissionHandler.CreatePermission) permissions.GET("", r.permissionHandler.ListPermissions) permissions.GET("/tree", r.permissionHandler.GetPermissionTree) permissions.GET("/:id", r.permissionHandler.GetPermission) permissions.PUT("/:id", r.permissionHandler.UpdatePermission) permissions.DELETE("/:id", r.permissionHandler.DeletePermission) permissions.PUT("/:id/status", r.permissionHandler.UpdatePermissionStatus) } devices := protected.Group("/devices") { devices.GET("", r.deviceHandler.GetMyDevices) devices.POST("", r.deviceHandler.CreateDevice) devices.GET("/:id", r.deviceHandler.GetDevice) devices.PUT("/:id", r.deviceHandler.UpdateDevice) devices.DELETE("/:id", r.deviceHandler.DeleteDevice) devices.PUT("/:id/status", r.deviceHandler.UpdateDeviceStatus) devices.POST("/:id/trust", r.deviceHandler.TrustDevice) devices.POST("/by-device-id/:deviceId/trust", r.deviceHandler.TrustDeviceByDeviceID) devices.DELETE("/:id/trust", r.deviceHandler.UntrustDevice) devices.GET("/me/trusted", r.deviceHandler.GetMyTrustedDevices) devices.POST("/me/logout-others", r.deviceHandler.LogoutAllOtherDevices) devices.GET("/users/:id", r.deviceHandler.GetUserDevices) } adminDevices := protected.Group("/admin/devices") adminDevices.Use(middleware.AdminOnly()) { adminDevices.GET("", r.deviceHandler.GetAllDevices) adminDevices.DELETE("/:id", r.deviceHandler.DeleteDevice) adminDevices.PUT("/:id/status", r.deviceHandler.UpdateDeviceStatus) adminDevices.POST("/:id/trust", r.deviceHandler.TrustDevice) adminDevices.DELETE("/:id/trust", r.deviceHandler.UntrustDevice) } if r.logHandler != nil { logs := protected.Group("/logs") { logs.GET("/login/me", r.logHandler.GetMyLoginLogs) logs.GET("/operation/me", r.logHandler.GetMyOperationLogs) adminLogs := logs.Group("") adminLogs.Use(middleware.AdminOnly()) { adminLogs.GET("/login", r.logHandler.GetLoginLogs) adminLogs.GET("/login/export", r.logHandler.ExportLoginLogs) adminLogs.GET("/operation", r.logHandler.GetOperationLogs) } } } if r.totpHandler != nil { twoFA := protected.Group("/auth/2fa") { twoFA.GET("/status", r.totpHandler.GetTOTPStatus) twoFA.GET("/setup", r.totpHandler.SetupTOTP) twoFA.POST("/enable", r.totpHandler.EnableTOTP) twoFA.POST("/disable", r.totpHandler.DisableTOTP) twoFA.POST("/verify", r.totpHandler.VerifyTOTP) } } if r.webhookHandler != nil { webhooks := protected.Group("/webhooks") { webhooks.POST("", r.webhookHandler.CreateWebhook) webhooks.GET("", r.webhookHandler.ListWebhooks) webhooks.PUT("/:id", r.webhookHandler.UpdateWebhook) webhooks.DELETE("/:id", r.webhookHandler.DeleteWebhook) webhooks.GET("/:id/deliveries", r.webhookHandler.GetWebhookDeliveries) } } if r.exportHandler != nil { adminUsers := protected.Group("/admin/users") adminUsers.Use(middleware.AdminOnly()) { adminUsers.GET("/export", r.exportHandler.ExportUsers) adminUsers.POST("/import", r.exportHandler.ImportUsers) adminUsers.GET("/import/template", r.exportHandler.GetImportTemplate) } } adminMgmt := protected.Group("/admin/admins") adminMgmt.Use(middleware.AdminOnly()) { adminMgmt.GET("", r.userHandler.ListAdmins) adminMgmt.POST("", r.userHandler.CreateAdmin) adminMgmt.DELETE("/:id", r.userHandler.DeleteAdmin) } if r.statsHandler != nil { adminStats := protected.Group("/admin/stats") adminStats.Use(middleware.AdminOnly()) { adminStats.GET("/dashboard", r.statsHandler.GetDashboard) adminStats.GET("/users", r.statsHandler.GetUserStats) } } if r.customFieldHandler != nil { // 自定义字段管理(管理员) customFields := protected.Group("/custom-fields") customFields.Use(middleware.AdminOnly()) { customFields.POST("", r.customFieldHandler.CreateField) customFields.GET("", r.customFieldHandler.ListFields) customFields.GET("/:id", r.customFieldHandler.GetField) customFields.PUT("/:id", r.customFieldHandler.UpdateField) customFields.DELETE("/:id", r.customFieldHandler.DeleteField) } // 用户自定义字段值(用户自己的) userFields := protected.Group("/users/me/custom-fields") { userFields.GET("", r.customFieldHandler.GetUserFieldValues) userFields.PUT("", r.customFieldHandler.SetUserFieldValues) } } if r.themeHandler != nil { // 主题管理(管理员) themes := protected.Group("/themes") themes.Use(middleware.AdminOnly()) { themes.POST("", r.themeHandler.CreateTheme) themes.GET("", r.themeHandler.ListAllThemes) themes.GET("/default", r.themeHandler.GetDefaultTheme) themes.PUT("/default/:id", r.themeHandler.SetDefaultTheme) themes.GET("/:id", r.themeHandler.GetTheme) themes.PUT("/:id", r.themeHandler.UpdateTheme) themes.DELETE("/:id", r.themeHandler.DeleteTheme) } } // SSO 单点登录接口(需要认证) if r.ssoHandler != nil { sso := protected.Group("/sso") { sso.GET("/authorize", r.ssoHandler.Authorize) sso.POST("/token", r.ssoHandler.Token) sso.POST("/introspect", r.ssoHandler.Introspect) sso.POST("/revoke", r.ssoHandler.Revoke) sso.GET("/userinfo", r.ssoHandler.UserInfo) } } } } return r.engine } func (r *Router) GetEngine() *gin.Engine { return r.engine }