Files

368 lines
14 KiB
Go
Raw Permalink Normal View History

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
}