Jelajahi Sumber

feat(admin): 添加 WAF 日志查询功能

- 在 HTTP 服务器中添加 WAF 日志查询相关路由
- 实现 WAF 日志查询的 API 结构和处理逻辑
- 添加 WAF 日志查询的数据库操作方法
-优化 WAF 日志列表查询,支持分页和筛选功能
fusu 6 hari lalu
induk
melakukan
7b48cdf4d0

+ 21 - 0
api/v1/admin/wafLog.go

@@ -12,4 +12,25 @@ type WafLog struct {
 	ApiName    string `json:"api_name" form:"api_name" gorm:"column:api_name"`
 	ApiType    string `json:"api_type" form:"api_type" gorm:"column:api_type"`
 	ExtraData  interface{} `json:"extra_data" form:"extra_data" gorm:"column:extra_data"`
+}
+
+type SearchWafLogParams struct {
+	Id         int    `json:"id" form:"id" gorm:"column:id;primary_key;AUTO_INCREMENT;not null"`
+	Uid        int    `json:"uid" form:"uid" gorm:"column:uid;default:0;not null"`
+	Name       string `json:"name" form:"name" gorm:"column:name"`
+	RequestIp  string `json:"request_ip" form:"request_ip" gorm:"column:request_ip"`
+	RuleId     int    `json:"rule_id" form:"rule_id" gorm:"column:rule_id;default:0"`
+	HostId     int    `json:"host_id" form:"host_id" gorm:"column:host_id;default:0"`
+	UserAgent  string `json:"user_agent" form:"user_agent" gorm:"column:user_agent"`
+	Api        string `json:"api" form:"api" gorm:"column:api"`
+	ApiName    string `json:"api_name" form:"api_name" gorm:"column:api_name"`
+	ApiType    string `json:"api_type" form:"api_type" gorm:"column:api_type"`
+	Current  int	`form:"current" json:"current" default:"1"`
+	PageSize int	`form:"pageSize" json:"pageSize" default:"10"`
+	Column   string `form:"column" json:"column" default:"id"`
+	Order    string `form:"order" json:"order" default:"desc"`
+}
+
+type WafLogId struct {
+	Id int `json:"id" form:"id" validate:"required,min=1"`
 }

+ 2 - 1
cmd/server/wire/wire_gen.go

@@ -118,7 +118,8 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	adminLogRepository := admin.NewLogRepository(repositoryRepository)
 	adminLogService := admin2.NewLogService(serviceService, adminLogRepository)
 	logHandler := admin3.NewLogHandler(handlerHandler, adminLogService)
-	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, syncedEnforcer, limiterLimiter, handlerFunc, userHandler, gameShieldHandler, gameShieldBackendHandler, webForwardingHandler, tcpforwardingHandler, udpForWardingHandler, globalLimitHandler, adminHandler, gatewayIpAdminHandler, allowAndDenyIpHandler, ccHandler, logService, ccIpListHandler, cdnLogHandler, logHandler)
+	wafLogHandler := admin3.NewWafLogHandler(handlerHandler, wafLogService)
+	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, syncedEnforcer, limiterLimiter, handlerFunc, userHandler, gameShieldHandler, gameShieldBackendHandler, webForwardingHandler, tcpforwardingHandler, udpForWardingHandler, globalLimitHandler, adminHandler, gatewayIpAdminHandler, allowAndDenyIpHandler, ccHandler, logService, ccIpListHandler, cdnLogHandler, logHandler, wafLogHandler)
 	appApp := newApp(httpServer)
 	return appApp, func() {
 		cleanup()

+ 31 - 1
internal/handler/admin/waflog.go

@@ -2,8 +2,12 @@ package admin
 
 import (
 	"github.com/gin-gonic/gin"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	adminApi "github.com/go-nunu/nunu-layout-advanced/api/v1/admin"
 	"github.com/go-nunu/nunu-layout-advanced/internal/handler"
 	"github.com/go-nunu/nunu-layout-advanced/internal/service/admin"
+	"github.com/mcuadros/go-defaults"
+	"net/http"
 )
 
 type WafLogHandler struct {
@@ -22,5 +26,31 @@ func NewWafLogHandler(
 }
 
 func (h *WafLogHandler) GetWafLog(ctx *gin.Context) {
-
+	var req adminApi.WafLog
+	if err := ctx.ShouldBind(&req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	defaults.SetDefaults(&req)
+	res, err := h.wafLogService.GetWafLog(ctx, int64(req.Id))
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, res)
 }
+
+func (h *WafLogHandler) GetWafLogList(ctx *gin.Context) {
+	var req adminApi.SearchWafLogParams
+	if err := ctx.ShouldBind(&req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	defaults.SetDefaults(&req)
+	res, err := h.wafLogService.GetWafLogList(ctx, req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, res)
+}

+ 106 - 3
internal/repository/admin/waflog.go

@@ -2,13 +2,17 @@ package admin
 
 import (
     "context"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	adminApi "github.com/go-nunu/nunu-layout-advanced/api/v1/admin"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"math"
+	"strings"
 )
 
 type WafLogRepository interface {
 	GetWafLog(ctx context.Context, id int64) (*model.WafLog, error)
-	GetWafLogList(ctx context.Context) ([]model.WafLog, error)
+	GetWafLogList(ctx context.Context, req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error)
 	AddWafLog(ctx context.Context, log *model.WafLog) error
 	BatchAddWafLog(ctx context.Context, logs []*model.WafLog) error
 }
@@ -30,9 +34,108 @@ func (r *wafLogRepository) GetWafLog(ctx context.Context, id int64) (*model.WafL
 	return &res, r.DBWithName(ctx,"admin").Where("id = ?", id).First(&res).Error
 }
 
-func (r *wafLogRepository) GetWafLogList(ctx context.Context) ([]model.WafLog, error) {
+func (r *wafLogRepository) GetWafLogList(ctx context.Context, req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error) {
 	var res []model.WafLog
-	return res, r.DBWithName(ctx,"admin").Find(&res).Error
+	var total int64
+
+	query := r.DBWithName(ctx,"admin").Model(&model.WafLog{})
+	if  req.RequestIp != "" {
+		trimmedName := strings.TrimSpace(req.RequestIp)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("request_ip LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+
+	if req.Uid != 0 {
+		query = query.Where("uid = ?", req.Uid)
+	}
+
+	if req.Api != "" {
+		trimmedName := strings.TrimSpace(req.Api)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("api LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+	if req.Name != "" {
+		trimmedName := strings.TrimSpace(req.Name)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("name LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+
+	if req.RuleId != 0 {
+		query = query.Where("rule_id = ?", req.RuleId)
+	}
+
+	if req.HostId != 0 {
+		query = query.Where("host_id = ?", req.HostId)
+	}
+
+	if req.Api != "" {
+		trimmedName := strings.TrimSpace(req.Api)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("api LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+	if req.UserAgent != "" {
+		trimmedName := strings.TrimSpace(req.UserAgent)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("user_agent LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+	if req.ApiName != "" {
+		trimmedName := strings.TrimSpace(req.ApiName)
+		// 使用 LIKE 进行模糊匹配
+		query = query.Where("api_name LIKE CONCAT('%', ?, '%')", trimmedName)
+	}
+
+	if req.ApiType != "" {
+		query = query.Where("api_type = ?", req.ApiType)
+	}
+
+
+	if req.Column != "" {
+		query = query.Order(req.Column + " " + req.Order)
+	}
+
+	if err := query.Count(&total).Error; err != nil {
+		// 如果连计数都失败了,直接返回错误
+		return nil, err
+	}
+
+
+	page := req.Current
+	pageSize := req.PageSize
+
+	if page <= 0 {
+		page = 1
+	}
+
+	if pageSize <= 0 {
+		pageSize = 10 // 默认每页 10 条
+	} else if pageSize > 100 {
+		pageSize = 100 // 每页最多 100 条
+	}
+
+	// 计算 offset (偏移量)
+	// 例如,第 1 页,offset = (1-1)*10 = 0 (从第0条开始)
+	// 第 2 页,offset = (2-1)*10 = 10 (从第10条开始)
+	offset := (page - 1) * pageSize
+	// 3. 执行最终的查询
+	// 在所有条件都添加完毕后,再执行 .Find()
+	result := query.Offset(offset).Limit(pageSize).Find(&res)
+	if result.Error != nil {
+		// 这里的错误可能是数据库连接问题等,而不是“未找到记录”
+		return nil, result.Error
+	}
+	return &v1.PaginatedResponse[model.WafLog]{
+		Records: res,
+		Page: page,
+		PageSize: pageSize,
+		Total: total,
+		TotalPages: int(math.Ceil(float64(total) / float64(pageSize))),
+
+	}, nil
 }
 
 func (r *wafLogRepository) AddWafLog(ctx context.Context, log *model.WafLog) error {

+ 3 - 0
internal/server/http.go

@@ -41,6 +41,7 @@ func NewHTTPServer(
 	ccIpListHandler *waf.CcIpListHandler,
 	cdnLogHandler *waf.CdnLogHandler,
 	logHandler *admin.LogHandler,
+	wafLogHandler *admin.WafLogHandler,
 ) *http.Server {
 	gin.SetMode(gin.DebugMode)
 	s := http.NewServer(
@@ -191,6 +192,8 @@ func NewHTTPServer(
 			strictAuthRouter.GET("/log/get", logHandler.GetLog)
 			strictAuthRouter.GET("/log/getList", logHandler.GetLogList)
 
+			strictAuthRouter.GET("/wafLog/get", wafLogHandler.GetWafLog)
+			strictAuthRouter.GET("/wafLog/getList", wafLogHandler.GetWafLogList)
 		}
 	}
 

+ 4 - 3
internal/service/admin/waflog.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	adminApi "github.com/go-nunu/nunu-layout-advanced/api/v1/admin"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	adminRep "github.com/go-nunu/nunu-layout-advanced/internal/repository/admin"
@@ -17,7 +18,7 @@ import (
 
 type WafLogService interface {
 	GetWafLog(ctx context.Context, id int64) (*model.WafLog, error)
-	GetWafLogList(ctx context.Context) ([]model.WafLog, error)
+	GetWafLogList(ctx context.Context, req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error)
 	AddWafLog(ctx context.Context, req adminApi.WafLog) error
 	BatchAddWafLog(ctx context.Context, reqs []*adminApi.WafLog) error
 	PublishIpWafLogTask(ctx context.Context, req adminApi.WafLog)
@@ -109,8 +110,8 @@ func (s *wafLogService) GetWafLog(ctx context.Context, id int64) (*model.WafLog,
 	return s.wafLogRepository.GetWafLog(ctx, id)
 }
 
-func (s *wafLogService) GetWafLogList(ctx context.Context) ([]model.WafLog, error) {
-	return s.wafLogRepository.GetWafLogList(ctx)
+func (s *wafLogService) GetWafLogList(ctx context.Context,req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error) {
+	return s.wafLogRepository.GetWafLogList(ctx, req)
 }
 
 func (s *wafLogService) AddWafLog(ctx context.Context, req adminApi.WafLog) error {