feat: add comprehensive operation logs for all critical actions
- Login/Logout: record user authentication events with source IP - Login failed: record failed login attempts for security audit - Export: record data export operations - Machine status change: record online/offline transitions with reason - SSH sync: record automatic SSH sync success/failure with error details - All auto-generated logs use username='system' and empty source_ip
This commit is contained in:
@@ -27,10 +27,16 @@ func (h *AuthHandler) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.Username != h.Cfg.AdminUser {
|
if req.Username != h.Cfg.AdminUser {
|
||||||
|
// 记录登录失败日志
|
||||||
|
var entityID int64 = 0
|
||||||
|
middleware.LogOperation("login_failed", "user", &entityID, req.Username, "", "invalid credentials", c.ClientIP(), req.Username)
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !checkPassword(req.Password, h.Cfg.AdminPass) {
|
if !checkPassword(req.Password, h.Cfg.AdminPass) {
|
||||||
|
// 记录登录失败日志
|
||||||
|
var entityID int64 = 0
|
||||||
|
middleware.LogOperation("login_failed", "user", &entityID, req.Username, "", "invalid credentials", c.ClientIP(), req.Username)
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -40,13 +46,22 @@ func (h *AuthHandler) Login(c *gin.Context) {
|
|||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 记录登录成功日志
|
||||||
|
var entityID int64 = 0
|
||||||
|
middleware.LogOperation("login", "user", &entityID, req.Username, "", "", c.ClientIP(), req.Username)
|
||||||
c.JSON(http.StatusOK, gin.H{"username": req.Username, "is_admin": true})
|
c.JSON(http.StatusOK, gin.H{"username": req.Username, "is_admin": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AuthHandler) Logout(c *gin.Context) {
|
func (h *AuthHandler) Logout(c *gin.Context) {
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
|
user := session.Get(middleware.AdminSessionKey)
|
||||||
session.Delete(middleware.AdminSessionKey)
|
session.Delete(middleware.AdminSessionKey)
|
||||||
_ = session.Save()
|
_ = session.Save()
|
||||||
|
// 记录登出日志
|
||||||
|
if user != nil {
|
||||||
|
var entityID int64 = 0
|
||||||
|
middleware.LogOperation("logout", "user", &entityID, user.(string), "", "", c.ClientIP(), user.(string))
|
||||||
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "logged out"})
|
c.JSON(http.StatusOK, gin.H{"message": "logged out"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ func (h *ExportHandler) Export(c *gin.Context) {
|
|||||||
b, _ := json.MarshalIndent(data, "", " ")
|
b, _ := json.MarshalIndent(data, "", " ")
|
||||||
filename := "lan-manager-backup-" + time.Now().Format("20060102") + ".json"
|
filename := "lan-manager-backup-" + time.Now().Format("20060102") + ".json"
|
||||||
c.Header("Content-Disposition", "attachment; filename="+filename)
|
c.Header("Content-Disposition", "attachment; filename="+filename)
|
||||||
|
|
||||||
|
// 记录导出日志
|
||||||
|
var entityID int64 = 0
|
||||||
|
middleware.LogOperation("export", "system", &entityID, "json-export", "", "", c.ClientIP(), middleware.CurrentUser(c))
|
||||||
|
|
||||||
c.Data(http.StatusOK, "application/json", b)
|
c.Data(http.StatusOK, "application/json", b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"lan-manager/server/db"
|
"lan-manager/server/db"
|
||||||
|
"lan-manager/server/middleware"
|
||||||
"lan-manager/server/models"
|
"lan-manager/server/models"
|
||||||
"lan-manager/server/utils"
|
"lan-manager/server/utils"
|
||||||
"net"
|
"net"
|
||||||
@@ -199,6 +200,9 @@ func handlePingResult(m *machinePing, res PingResult) {
|
|||||||
fmt.Printf("[Ping] %s -> online=false, reason=%s\n", m.ip, reason)
|
fmt.Printf("[Ping] %s -> online=false, reason=%s\n", m.ip, reason)
|
||||||
}
|
}
|
||||||
_, _ = db.DB.Exec(`INSERT INTO offline_logs (machine_id, reason, started_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, m.id, reason)
|
_, _ = db.DB.Exec(`INSERT INTO offline_logs (machine_id, reason, started_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, m.id, reason)
|
||||||
|
// 记录状态变化日志
|
||||||
|
var entityID int64 = m.id
|
||||||
|
middleware.LogOperation("status_change", "machine", &entityID, m.ip, "online", "offline: "+reason, "", "system")
|
||||||
m.wasOnline = false
|
m.wasOnline = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -219,6 +223,9 @@ func handlePingResult(m *machinePing, res PingResult) {
|
|||||||
_, _ = db.DB.Exec(`UPDATE offline_logs SET ended_at=CURRENT_TIMESTAMP, duration_seconds=? WHERE id=?`, duration, logID)
|
_, _ = db.DB.Exec(`UPDATE offline_logs SET ended_at=CURRENT_TIMESTAMP, duration_seconds=? WHERE id=?`, duration, logID)
|
||||||
_, _ = db.DB.Exec(`UPDATE machines SET total_offline_seconds=total_offline_seconds+? WHERE id=?`, duration, m.id)
|
_, _ = db.DB.Exec(`UPDATE machines SET total_offline_seconds=total_offline_seconds+? WHERE id=?`, duration, m.id)
|
||||||
}
|
}
|
||||||
|
// 记录状态恢复日志
|
||||||
|
var entityID int64 = m.id
|
||||||
|
middleware.LogOperation("status_change", "machine", &entityID, m.ip, "offline", "online", "", "system")
|
||||||
m.wasOnline = true
|
m.wasOnline = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -338,9 +345,15 @@ func StartSSHSyncService() {
|
|||||||
result, err := GetSSHInfo(machine.ip, machine.sshPort, machine.username, plainPass)
|
result, err := GetSSHInfo(machine.ip, machine.sshPort, machine.username, plainPass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[SSH] sync failed for %s:%d: %v\n", machine.ip, machine.sshPort, err)
|
fmt.Printf("[SSH] sync failed for %s:%d: %v\n", machine.ip, machine.sshPort, err)
|
||||||
|
// 记录 SSH 同步失败日志
|
||||||
|
var entityID int64 = machine.id
|
||||||
|
middleware.LogOperation("sync_ssh_failed", "machine", &entityID, machine.ip, "", err.Error(), "", "system")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
saveSSHResult(machine.id, machine.ip, machine.sshPort, result)
|
saveSSHResult(machine.id, machine.ip, machine.sshPort, result)
|
||||||
|
// 记录 SSH 同步成功日志
|
||||||
|
var entityID int64 = machine.id
|
||||||
|
middleware.LogOperation("sync_ssh", "machine", &entityID, machine.ip, "", "success", "", "system")
|
||||||
}(m)
|
}(m)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|||||||
Reference in New Issue
Block a user