This commit is contained in:
Mrx
2026-03-20 13:24:45 +08:00
parent 3779a7d66d
commit 521bfeb4ef
15 changed files with 530 additions and 40 deletions

View File

@@ -0,0 +1,168 @@
package handlers
import (
"strconv"
"strings"
"time"
securityEntities "tyapi-server/internal/domains/security/entities"
"tyapi-server/internal/shared/interfaces"
"tyapi-server/internal/shared/ipgeo"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm"
)
// AdminSecurityHandler 管理员安全数据处理器
type AdminSecurityHandler struct {
db *gorm.DB
responseBuilder interfaces.ResponseBuilder
logger *zap.Logger
ipLocator *ipgeo.Locator
}
func NewAdminSecurityHandler(
db *gorm.DB,
responseBuilder interfaces.ResponseBuilder,
logger *zap.Logger,
ipLocator *ipgeo.Locator,
) *AdminSecurityHandler {
return &AdminSecurityHandler{
db: db,
responseBuilder: responseBuilder,
logger: logger,
ipLocator: ipLocator,
}
}
func (h *AdminSecurityHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
if value := c.Query(key); value != "" {
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
return intValue
}
}
return defaultValue
}
func (h *AdminSecurityHandler) parseRange(c *gin.Context) (time.Time, time.Time, bool) {
startTime := time.Now().Add(-24 * time.Hour)
endTime := time.Now()
if start := strings.TrimSpace(c.Query("start_time")); start != "" {
t, err := time.Parse("2006-01-02 15:04:05", start)
if err != nil {
h.responseBuilder.BadRequest(c, "start_time格式错误示例2026-03-19 10:00:00")
return time.Time{}, time.Time{}, false
}
startTime = t
}
if end := strings.TrimSpace(c.Query("end_time")); end != "" {
t, err := time.Parse("2006-01-02 15:04:05", end)
if err != nil {
h.responseBuilder.BadRequest(c, "end_time格式错误示例2026-03-19 12:00:00")
return time.Time{}, time.Time{}, false
}
endTime = t
}
return startTime, endTime, true
}
// ListSuspiciousIPs 获取可疑IP列表
func (h *AdminSecurityHandler) ListSuspiciousIPs(c *gin.Context) {
page := h.getIntQuery(c, "page", 1)
pageSize := h.getIntQuery(c, "page_size", 20)
if pageSize > 100 {
pageSize = 100
}
startTime, endTime, ok := h.parseRange(c)
if !ok {
return
}
ip := strings.TrimSpace(c.Query("ip"))
path := strings.TrimSpace(c.Query("path"))
query := h.db.Model(&securityEntities.SuspiciousIPRecord{}).
Where("created_at >= ? AND created_at <= ?", startTime, endTime)
if ip != "" {
query = query.Where("ip = ?", ip)
}
if path != "" {
query = query.Where("path LIKE ?", "%"+path+"%")
}
var total int64
if err := query.Count(&total).Error; err != nil {
h.logger.Error("查询可疑IP总数失败", zap.Error(err))
h.responseBuilder.InternalError(c, "查询失败")
return
}
var items []securityEntities.SuspiciousIPRecord
if err := query.Order("created_at DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&items).Error; err != nil {
h.logger.Error("查询可疑IP列表失败", zap.Error(err))
h.responseBuilder.InternalError(c, "查询失败")
return
}
h.responseBuilder.Success(c, gin.H{
"items": items,
"total": total,
}, "获取成功")
}
type geoStreamRow struct {
IP string `json:"ip"`
Path string `json:"path"`
Count int `json:"count"`
}
// GetSuspiciousIPGeoStream 获取地球请求流数据
func (h *AdminSecurityHandler) GetSuspiciousIPGeoStream(c *gin.Context) {
startTime, endTime, ok := h.parseRange(c)
if !ok {
return
}
topN := h.getIntQuery(c, "top_n", 200)
if topN > 1000 {
topN = 1000
}
var rows []geoStreamRow
err := h.db.Model(&securityEntities.SuspiciousIPRecord{}).
Select("ip, path, COUNT(1) as count").
Where("created_at >= ? AND created_at <= ?", startTime, endTime).
Group("ip, path").
Order("count DESC").
Limit(topN).
Scan(&rows).Error
if err != nil {
h.logger.Error("查询地球请求流失败", zap.Error(err))
h.responseBuilder.InternalError(c, "查询失败")
return
}
// 目标固定服务器点位(上海)
const serverName = "TYAPI-Server"
const serverLng = 121.4737
const serverLat = 31.2304
result := make([]gin.H, 0, len(rows))
for _, row := range rows {
record := securityEntities.SuspiciousIPRecord{IP: row.IP}
fromName, fromLng, fromLat := h.ipLocator.ToGeoPoint(record)
result = append(result, gin.H{
"from_name": fromName,
"from_lng": fromLng,
"from_lat": fromLat,
"to_name": serverName,
"to_lng": serverLng,
"to_lat": serverLat,
"value": row.Count,
"path": row.Path,
"ip": row.IP,
})
}
h.responseBuilder.Success(c, result, "获取成功")
}