368 lines
14 KiB
Go
368 lines
14 KiB
Go
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
|
|
}
|