From 83a1c5ca8af49343ce8f8518b24eb99f2746e0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=87=E5=B3=B0?= Date: Tue, 28 Apr 2026 17:48:19 +0800 Subject: [PATCH] up --- .workbuddy/memory/2026-04-28.md | 7 +++ backend/my_work/routers/apiUsers.go | 70 ++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/.workbuddy/memory/2026-04-28.md b/.workbuddy/memory/2026-04-28.md index a4f6108..a139e79 100644 --- a/.workbuddy/memory/2026-04-28.md +++ b/.workbuddy/memory/2026-04-28.md @@ -29,3 +29,10 @@ - `show-workorder.vue` → `printWorkOrder()` - `item-detail.vue` → `printItem()` - `warehouse.vue` → `printContainer()` + +## 用户登录失败日志表 + +- `apiUsers.go` 新增 `TabUserLoginFailLog` 表结构:记录 `username`、`userID`、`IP`、`userAgent`、`reason`(password_error / user_not_found)、`count`(连续失败次数)、`created_at`、`updated_at` +- `InitUsersRouter` 中新增 `AutoMigrate(&TabUserLoginFailLog{})` +- 登录成功时清除该用户失败记录;密码错误和用户不存在时调用 `recordLoginFail()` 记录/更新失败日志(24小时内累计次数) +- `recordLoginFail()` 在 `TabUserLoginFailLog` 结构体后定义 diff --git a/backend/my_work/routers/apiUsers.go b/backend/my_work/routers/apiUsers.go index b5f70eb..4b17ce3 100644 --- a/backend/my_work/routers/apiUsers.go +++ b/backend/my_work/routers/apiUsers.go @@ -66,6 +66,64 @@ type TabUserCookie struct { Remember bool `gorm:"default:false"` } +// TabUserLoginFailLog 用户登录失败日志表 +type TabUserLoginFailLog struct { + ID uint `gorm:"primaryKey;autoIncrement"` + Username string `gorm:"size:100;index"` // 尝试登录的用户名 + UserID uint `gorm:"index;default:0"` // 用户ID(如果用户存在) + IP string `gorm:"size:64"` // 登录IP + UserAgent string `gorm:"size:512"` // User-Agent + Reason string `gorm:"size:64"` // 失败原因:password_error / user_not_found + Count int `gorm:"default:1"` // 连续失败次数 + CreatedAt time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 首次失败时间 + UpdatedAt time.Time `gorm:"type:datetime;index;default:CURRENT_TIMESTAMP"` // 最后失败时间 +} + +var ( + sysUserGroup TabUserGroups + sysAdmins []uint +) + +func updateSysAdminsCash() { + +} + +// recordLoginFail 记录登录失败日志,更新连续失败次数 +func recordLoginFail(ctx *gin.Context, username string, userID uint, reason string) { + // 获取客户端IP和UserAgent + ip := ctx.ClientIP() + userAgent := ctx.GetHeader("User-Agent") + + // 查找是否有该用户最近的失败记录(24小时内) + var existingLog TabUserLoginFailLog + err := models.DB.Where("username = ? AND reason = ? AND updated_at > ?", + username, reason, time.Now().Add(-24*time.Hour)). + Order("id DESC").First(&existingLog).Error + + if err == nil { + // 存在最近失败的记录,更新次数 + models.DB.Model(&existingLog).Updates(map[string]interface{}{ + "count": existingLog.Count + 1, + "ip": ip, + "user_agent": userAgent, + "updated_at": time.Now(), + }) + } else { + // 不存在,创建新记录 + newLog := TabUserLoginFailLog{ + Username: username, + UserID: userID, + IP: ip, + UserAgent: userAgent, + Reason: reason, + Count: 1, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + models.DB.Create(&newLog) + } +} + func HashUserPass(user *TabUser) { switch models.ConfigsUser.PassHashType { case "text": @@ -119,6 +177,8 @@ func ApiUserInit() { models.DB.AutoMigrate(&TabUserCookie{}) + models.DB.AutoMigrate(&TabUserLoginFailLog{}) + //创建admin用户 var user TabUser user.Name = "admin" @@ -156,6 +216,8 @@ func ApiUserInit() { models.DB.Create(&usergroupbind) // 传入指针 } + //更新系统管理员列表 + updateSysAdminsCash() } type From_user_add struct { @@ -542,17 +604,23 @@ func ApiUser(r *gin.RouterGroup) { } models.DB.Create(&cookie) // 传入指针 + // 登录成功,清除该用户的失败记录 + models.DB.Where("username = ?", loginuser.Username).Delete(&TabUserLoginFailLog{}) + redata := map[string]interface{}{ "cookie": cookie, } ReturnJson(ctx, "apiOK", redata) } else { + // 密码错误,记录失败日志 + recordLoginFail(ctx, loginuser.Username, getuser.ID, "password_error") ReturnJson(ctx, "userPassIncorrect", nil) } } else { - //用户不存在 + //用户不存在,记录失败日志 + recordLoginFail(ctx, loginuser.Username, 0, "user_not_found") ReturnJson(ctx, "userNameNoFund", nil) }