- 前端: React 18 + TypeScript + Vite + Tailwind CSS + shadcn/ui - 后端: Go + Gin + GORM + JWT (golang-jwt/jwt/v5) - 功能: 服务器管理、K8s集群、监控告警、CI/CD、自动化运维、审批流程、审计日志 - 文档: 设计文档(ROADMAP/PDD/架构/模块)
363 lines
10 KiB
Go
363 lines
10 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"ezops/internal/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// AuditHandler 审计日志处理器
|
|
type AuditHandler struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAuditHandler 创建审计日志处理器
|
|
func NewAuditHandler(db *gorm.DB) *AuditHandler {
|
|
return &AuditHandler{db: db}
|
|
}
|
|
|
|
// ListAuditLogs 获取审计日志列表
|
|
// @Summary 获取审计日志列表
|
|
// @Description 获取审计日志列表,支持分页和筛选
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param page query int false "页码" default(1)
|
|
// @Param pageSize query int false "每页数量" default(20)
|
|
// @Param module query string false "模块"
|
|
// @Param action query string false "操作类型"
|
|
// @Param username query string false "用户名"
|
|
// @Param startTime query string false "开始时间"
|
|
// @Param endTime query string false "结束时间"
|
|
// @Success 200 {object} models.AuditLogListResponse
|
|
// @Router /api/v1/audit/logs [get]
|
|
func (h *AuditHandler) ListAuditLogs(c *gin.Context) {
|
|
var req models.AuditLogQuery
|
|
if err := c.ShouldBindQuery(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()})
|
|
return
|
|
}
|
|
|
|
// 设置默认值
|
|
if req.Page <= 0 {
|
|
req.Page = 1
|
|
}
|
|
if req.PageSize <= 0 {
|
|
req.PageSize = 20
|
|
}
|
|
|
|
// 构建查询
|
|
query := h.db.Model(&models.AuditLog{})
|
|
|
|
if req.Module != "" {
|
|
query = query.Where("module = ?", req.Module)
|
|
}
|
|
if req.Action != "" {
|
|
query = query.Where("action = ?", req.Action)
|
|
}
|
|
if req.Username != "" {
|
|
query = query.Where("username LIKE ?", "%"+req.Username+"%")
|
|
}
|
|
if req.StartTime != "" {
|
|
query = query.Where("created_at >= ?", req.StartTime)
|
|
}
|
|
if req.EndTime != "" {
|
|
query = query.Where("created_at <= ?", req.EndTime)
|
|
}
|
|
|
|
// 获取总数
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"})
|
|
return
|
|
}
|
|
|
|
// 获取列表
|
|
var logs []models.AuditLog
|
|
if err := query.Order("created_at DESC").
|
|
Offset((req.Page - 1) * req.PageSize).
|
|
Limit(req.PageSize).
|
|
Find(&logs).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, models.AuditLogListResponse{
|
|
List: logs,
|
|
Total: total,
|
|
})
|
|
}
|
|
|
|
// GetAuditLogDetail 获取审计日志详情
|
|
// @Summary 获取审计日志详情
|
|
// @Description 获取指定ID的审计日志详情
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "日志ID"
|
|
// @Success 200 {object} models.AuditLog
|
|
// @Router /api/v1/audit/logs/{id} [get]
|
|
func (h *AuditHandler) GetAuditLogDetail(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的日志ID"})
|
|
return
|
|
}
|
|
|
|
var log models.AuditLog
|
|
if err := h.db.First(&log, id).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "日志不存在"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, log)
|
|
}
|
|
|
|
// GetAuditModules 获取审计模块列表
|
|
// @Summary 获取审计模块列表
|
|
// @Description 获取所有审计模块类型
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/audit/modules [get]
|
|
func (h *AuditHandler) GetAuditModules(c *gin.Context) {
|
|
modules := []map[string]string{
|
|
{"value": "user", "label": "用户管理"},
|
|
{"value": "server", "label": "服务器管理"},
|
|
{"value": "k8s", "label": "Kubernetes"},
|
|
{"value": "alert", "label": "监控告警"},
|
|
{"value": "pipeline", "label": "应用发布"},
|
|
{"value": "automation", "label": "自动化运维"},
|
|
{"value": "approval", "label": "审批流程"},
|
|
{"value": "navigation", "label": "站内导航"},
|
|
{"value": "cloud_account", "label": "云账号管理"},
|
|
{"value": "domain", "label": "域名管理"},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": modules})
|
|
}
|
|
|
|
// GetAuditActions 获取审计操作类型列表
|
|
// @Summary 获取审计操作类型列表
|
|
// @Description 获取所有审计操作类型
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/audit/actions [get]
|
|
func (h *AuditHandler) GetAuditActions(c *gin.Context) {
|
|
actions := []map[string]string{
|
|
{"value": "create", "label": "创建"},
|
|
{"value": "update", "label": "更新"},
|
|
{"value": "delete", "label": "删除"},
|
|
{"value": "view", "label": "查看"},
|
|
{"value": "login", "label": "登录"},
|
|
{"value": "logout", "label": "登出"},
|
|
{"value": "execute", "label": "执行"},
|
|
{"value": "approve", "label": "审批"},
|
|
{"value": "reject", "label": "驳回"},
|
|
{"value": "import", "label": "导入"},
|
|
{"value": "export", "label": "导出"},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"data": actions})
|
|
}
|
|
|
|
// ExportAuditLogs 导出审计日志
|
|
// @Summary 导出审计日志
|
|
// @Description 导出审计日志为Excel或CSV
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param module query string false "模块"
|
|
// @Param action query string false "操作类型"
|
|
// @Param username query string false "用户名"
|
|
// @Param startTime query string false "开始时间"
|
|
// @Param endTime query string false "结束时间"
|
|
// @Param format query string false "导出格式" default("csv") Enums(csv, excel)
|
|
// @Success 200 {file} binary
|
|
// @Router /api/v1/audit/logs/export [get]
|
|
func (h *AuditHandler) ExportAuditLogs(c *gin.Context) {
|
|
var req models.AuditLogQuery
|
|
if err := c.ShouldBindQuery(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()})
|
|
return
|
|
}
|
|
|
|
// 构建查询
|
|
query := h.db.Model(&models.AuditLog{})
|
|
|
|
if req.Module != "" {
|
|
query = query.Where("module = ?", req.Module)
|
|
}
|
|
if req.Action != "" {
|
|
query = query.Where("action = ?", req.Action)
|
|
}
|
|
if req.Username != "" {
|
|
query = query.Where("username LIKE ?", "%"+req.Username+"%")
|
|
}
|
|
if req.StartTime != "" {
|
|
query = query.Where("created_at >= ?", req.StartTime)
|
|
}
|
|
if req.EndTime != "" {
|
|
query = query.Where("created_at <= ?", req.EndTime)
|
|
}
|
|
|
|
// 获取数据
|
|
var logs []models.AuditLog
|
|
if err := query.Order("created_at DESC").Find(&logs).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "导出失败"})
|
|
return
|
|
}
|
|
|
|
// TODO: 实现CSV/Excel导出功能
|
|
// 这里返回JSON格式的数据,实际项目中应该生成CSV或Excel文件
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "导出成功",
|
|
"count": len(logs),
|
|
"data": logs,
|
|
})
|
|
}
|
|
|
|
// GetAuditStatistics 获取审计统计
|
|
// @Summary 获取审计统计
|
|
// @Description 获取审计日志统计信息
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param days query int false "统计天数" default(7)
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/audit/statistics [get]
|
|
func (h *AuditHandler) GetAuditStatistics(c *gin.Context) {
|
|
days, _ := strconv.Atoi(c.DefaultQuery("days", "7"))
|
|
if days <= 0 {
|
|
days = 7
|
|
}
|
|
|
|
startTime := time.Now().AddDate(0, 0, -days)
|
|
|
|
// 统计各模块的操作数量
|
|
var moduleStats []struct {
|
|
Module string `json:"module"`
|
|
Count int64 `json:"count"`
|
|
}
|
|
h.db.Model(&models.AuditLog{}).
|
|
Select("module, COUNT(*) as count").
|
|
Where("created_at >= ?", startTime).
|
|
Group("module").
|
|
Scan(&moduleStats)
|
|
|
|
// 统计各操作类型的数量
|
|
var actionStats []struct {
|
|
Action string `json:"action"`
|
|
Count int64 `json:"count"`
|
|
}
|
|
h.db.Model(&models.AuditLog{}).
|
|
Select("action, COUNT(*) as count").
|
|
Where("created_at >= ?", startTime).
|
|
Group("action").
|
|
Scan(&actionStats)
|
|
|
|
// 统计每日操作数量
|
|
var dailyStats []struct {
|
|
Date string `json:"date"`
|
|
Count int64 `json:"count"`
|
|
}
|
|
h.db.Model(&models.AuditLog{}).
|
|
Select("DATE(created_at) as date, COUNT(*) as count").
|
|
Where("created_at >= ?", startTime).
|
|
Group("DATE(created_at)").
|
|
Order("date").
|
|
Scan(&dailyStats)
|
|
|
|
// 总记录数
|
|
var totalCount int64
|
|
h.db.Model(&models.AuditLog{}).Count(&totalCount)
|
|
|
|
// 今日记录数
|
|
today := time.Now().Format("2006-01-02")
|
|
var todayCount int64
|
|
h.db.Model(&models.AuditLog{}).
|
|
Where("DATE(created_at) = ?", today).
|
|
Count(&todayCount)
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"total_count": totalCount,
|
|
"today_count": todayCount,
|
|
"module_stats": moduleStats,
|
|
"action_stats": actionStats,
|
|
"daily_stats": dailyStats,
|
|
})
|
|
}
|
|
|
|
// ClearAuditLogs 清理审计日志
|
|
// @Summary 清理审计日志
|
|
// @Description 清理指定日期之前的审计日志
|
|
// @Tags 审计日志
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body map[string]string true "清理请求"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/audit/logs/clear [post]
|
|
func (h *AuditHandler) ClearAuditLogs(c *gin.Context) {
|
|
var req struct {
|
|
BeforeDate string `json:"before_date" binding:"required"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的请求参数"})
|
|
return
|
|
}
|
|
|
|
// 解析日期
|
|
beforeDate, err := time.Parse("2006-01-02", req.BeforeDate)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的日期格式"})
|
|
return
|
|
}
|
|
|
|
// 删除指定日期之前的日志
|
|
result := h.db.Where("created_at < ?", beforeDate).Delete(&models.AuditLog{})
|
|
if result.Error != nil {
|
|
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "清理失败"})
|
|
return
|
|
}
|
|
|
|
// 记录审计日志
|
|
userID, _ := c.Get("userID")
|
|
username, _ := c.Get("username")
|
|
h.RecordAuditLog(userID.(uint), username.(string), "audit", "clear", "清理审计日志", gin.H{
|
|
"before_date": req.BeforeDate,
|
|
"deleted": result.RowsAffected,
|
|
})
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "清理成功",
|
|
"deleted": result.RowsAffected,
|
|
})
|
|
}
|
|
|
|
// RecordAuditLog 记录审计日志
|
|
func (h *AuditHandler) RecordAuditLog(userID uint, username, module, action, description string, details interface{}) {
|
|
uid := userID
|
|
log := models.AuditLog{
|
|
UserID: &uid,
|
|
Username: username,
|
|
Module: module,
|
|
Action: action,
|
|
Resource: description,
|
|
}
|
|
|
|
h.db.Create(&log)
|
|
}
|