加固后台管理安全

This commit is contained in:
yml2213
2026-06-11 07:23:00 +08:00
parent 5255b21141
commit 88b1df64e7
41 changed files with 1276 additions and 293 deletions
+31 -10
View File
@@ -2,7 +2,6 @@ package router
import (
"context"
"os"
"strings"
"hfb_sys/backend/internal/config"
@@ -63,7 +62,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
if cfg.RateLimit.Enabled {
engine.Use(middleware.RateLimitPerMinute(cfg.RateLimit.RequestsPerMinute))
engine.Use(middleware.RateLimitPerMinute(cfg.RateLimit.RequestsPerMinute, deps.Redis))
}
jwtManager := auth.NewJWTManager(cfg.JWTSecret)
@@ -166,8 +165,8 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
var paymentConfigService *paymentconfig.Service
var paymentConfigHandler *paymentconfig.Handler
if deps.DB != nil {
// 从环境变量获取加密密钥,如果没有则使用 MockEncryptor
encryptionKey := os.Getenv("PAYMENT_CONFIG_ENCRYPTION_KEY")
// 生产环境必须配置有效加密密钥;开发/测试缺失时才降级 MockEncryptor
encryptionKey := cfg.PaymentConfigEncryptionKey
var encryptor paymentconfig.Encryptor
if encryptionKey != "" {
if aesEncryptor, err := paymentconfig.NewAESEncryptor(encryptionKey); err == nil {
@@ -175,6 +174,9 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
}
}
if encryptor == nil {
if cfg.AppEnv == "production" {
logger.Fatal("PAYMENT_CONFIG_ENCRYPTION_KEY not set or invalid")
}
encryptor = &paymentconfig.MockEncryptor{}
logger.Warn("PAYMENT_CONFIG_ENCRYPTION_KEY not set or invalid, using MockEncryptor")
}
@@ -225,7 +227,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
systemConfigHandler := systemconfig.NewHandler(systemConfigService)
var adminRoleRepo *adminrole.Repository
if deps.DB != nil {
adminRoleRepo = adminrole.NewRepository(deps.DB)
adminRoleRepo = adminrole.NewRepository(deps.DB, deps.Redis)
}
adminRoleService := adminrole.NewService(adminRoleRepo)
adminRoleHandler := adminrole.NewHandler(adminRoleService)
@@ -246,7 +248,10 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
fileService := filemodule.NewService(fileStorage)
fileHandler := filemodule.NewHandler(fileService, fileStorage)
listingService := listing.NewService(listingRepo, systemConfigRepo)
listingHandler := listing.NewHandler(listingService, fileStorage)
listingHandler := listing.NewHandler(listingService, fileStorage, listing.HandlerOptions{
ExternalUploadSecret: cfg.ExternalUploadSecret,
ExternalUploadAllowedIPs: cfg.ExternalUploadAllowedIPs,
})
var announcementRepo *announcement.Repository
if deps.DB != nil {
announcementRepo = announcement.NewRepository(deps.DB)
@@ -254,7 +259,20 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
announcementService := announcement.NewService(announcementRepo)
announcementHandler := announcement.NewHandler(announcementService)
requireAuth := middleware.Auth(jwtManager)
requireAdmin := middleware.AdminAuth(jwtManager)
var validateAdminToken middleware.AdminTokenValidatorFunc
if adminAuthRepo != nil {
validateAdminToken = func(ctx context.Context, adminID uint64, tokenVersion int64) (middleware.AdminTokenContext, error) {
admin, err := adminAuthRepo.FindActiveForToken(ctx, adminID, tokenVersion)
if err != nil {
return middleware.AdminTokenContext{}, err
}
return middleware.AdminTokenContext{
Username: admin.Username,
PasswordMustChange: admin.PasswordMustChange,
}, nil
}
}
requireAdmin := middleware.AdminAuth(jwtManager, validateAdminToken)
requireRealname := middleware.RequireRealname(userRepo)
requirePerm := func(code string) gin.HandlerFunc {
return middleware.RequirePermission(code, deps.Redis)
@@ -410,7 +428,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
adminAuthRoutes.POST("/refresh", adminAuthHandler.Refresh)
}
adminRoutes := api.Group("/admin", requireAdmin)
adminRoutes := api.Group("/admin", requireAdmin, middleware.RequireAdminPasswordChanged())
{
adminRoutes.GET("/me", adminAuthHandler.Me)
adminRoutes.PUT("/me/support-status", adminAuthHandler.UpdateSupportStatus)
@@ -455,7 +473,9 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
adminRoutes.GET("/payment-configs", requirePerm("payment_config:list"), paymentConfigHandler.List)
adminRoutes.GET("/payment-configs/export", requirePerm("payment_config:view_secret"), paymentConfigHandler.ExportBackup)
adminRoutes.POST("/payment-configs/import", requirePerm("payment_config:view_secret"), paymentConfigHandler.ImportBackup)
adminRoutes.GET("/payment-configs/:id", requirePerm("payment_config:list"), paymentConfigHandler.Get)
adminRoutes.GET("/payment-configs/:id", requirePerm("payment_config:list"), middleware.RequirePermissionIf("payment_config:view_secret", deps.Redis, func(c *gin.Context) bool {
return c.Query("include_secret") == "true"
}), paymentConfigHandler.Get)
adminRoutes.POST("/payment-configs", requirePerm("payment_config:create"), paymentConfigHandler.Create)
adminRoutes.PUT("/payment-configs/:id", requirePerm("payment_config:update"), paymentConfigHandler.Update)
adminRoutes.DELETE("/payment-configs/:id", requirePerm("payment_config:delete"), paymentConfigHandler.Delete)
@@ -498,7 +518,8 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
adminRoutes.PUT("/admin-users/:id", requirePerm("admin_user:manage"), adminMgrHandler.Update)
adminRoutes.DELETE("/admin-users/:id", requirePerm("admin_user:manage"), adminMgrHandler.Delete)
adminRoutes.PUT("/admin-users/:id/roles", requirePerm("admin_user:manage"), adminMgrHandler.AssignRoles)
adminRoutes.PUT("/admin-users/:id/password", adminMgrHandler.ChangePassword)
adminRoutes.PUT("/admin-users/me/password", adminMgrHandler.ChangeOwnPassword)
adminRoutes.PUT("/admin-users/:id/password", requirePerm("admin_user:manage"), adminMgrHandler.ResetPassword)
// 公告管理
adminRoutes.GET("/announcements", requirePerm("announcement:view"), announcementHandler.AdminList)