up
This commit is contained in:
@@ -29,3 +29,10 @@
|
|||||||
- `show-workorder.vue` → `printWorkOrder()`
|
- `show-workorder.vue` → `printWorkOrder()`
|
||||||
- `item-detail.vue` → `printItem()`
|
- `item-detail.vue` → `printItem()`
|
||||||
- `warehouse.vue` → `printContainer()`
|
- `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` 结构体后定义
|
||||||
|
|||||||
@@ -66,6 +66,64 @@ type TabUserCookie struct {
|
|||||||
Remember bool `gorm:"default:false"`
|
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) {
|
func HashUserPass(user *TabUser) {
|
||||||
switch models.ConfigsUser.PassHashType {
|
switch models.ConfigsUser.PassHashType {
|
||||||
case "text":
|
case "text":
|
||||||
@@ -119,6 +177,8 @@ func ApiUserInit() {
|
|||||||
|
|
||||||
models.DB.AutoMigrate(&TabUserCookie{})
|
models.DB.AutoMigrate(&TabUserCookie{})
|
||||||
|
|
||||||
|
models.DB.AutoMigrate(&TabUserLoginFailLog{})
|
||||||
|
|
||||||
//创建admin用户
|
//创建admin用户
|
||||||
var user TabUser
|
var user TabUser
|
||||||
user.Name = "admin"
|
user.Name = "admin"
|
||||||
@@ -156,6 +216,8 @@ func ApiUserInit() {
|
|||||||
models.DB.Create(&usergroupbind) // 传入指针
|
models.DB.Create(&usergroupbind) // 传入指针
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//更新系统管理员列表
|
||||||
|
updateSysAdminsCash()
|
||||||
}
|
}
|
||||||
|
|
||||||
type From_user_add struct {
|
type From_user_add struct {
|
||||||
@@ -542,17 +604,23 @@ func ApiUser(r *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
models.DB.Create(&cookie) // 传入指针
|
models.DB.Create(&cookie) // 传入指针
|
||||||
|
|
||||||
|
// 登录成功,清除该用户的失败记录
|
||||||
|
models.DB.Where("username = ?", loginuser.Username).Delete(&TabUserLoginFailLog{})
|
||||||
|
|
||||||
redata := map[string]interface{}{
|
redata := map[string]interface{}{
|
||||||
"cookie": cookie,
|
"cookie": cookie,
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnJson(ctx, "apiOK", redata)
|
ReturnJson(ctx, "apiOK", redata)
|
||||||
} else {
|
} else {
|
||||||
|
// 密码错误,记录失败日志
|
||||||
|
recordLoginFail(ctx, loginuser.Username, getuser.ID, "password_error")
|
||||||
ReturnJson(ctx, "userPassIncorrect", nil)
|
ReturnJson(ctx, "userPassIncorrect", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//用户不存在
|
//用户不存在,记录失败日志
|
||||||
|
recordLoginFail(ctx, loginuser.Username, 0, "user_not_found")
|
||||||
ReturnJson(ctx, "userNameNoFund", nil)
|
ReturnJson(ctx, "userNameNoFund", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user