feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
367
internal/api/router/router.go
Normal file
367
internal/api/router/router.go
Normal file
@@ -0,0 +1,367 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user