RunnerGo实现5次登录密码失败后,锁定10分钟后解锁的功能

发布于:2025-03-14 ⋅ 阅读:(20) ⋅ 点赞:(0)

效果展示

简单思路

RunnerGo实现5次登录密码失败后,锁定10分钟后解锁的功能,可以通过以下步骤和思路来实现‌:
记录登录失败次数和锁定状态 ‌:
在用户每次尝试登录时,检查是否输入错误密码。如果是错误密码,则增加错误次数计数器。
当错误次数达到5次时,记录当前时间作为锁定时间。
存储用户的登录失败次数和锁定时间在数据库中,可以使用Redis等键值存储来高效管理这些数据‌。
设置锁定时间和解锁机制 ‌:
当用户达到5次登录失败后,系统将用户的账户锁定,并记录锁定时间为当前时间加上10分钟。
用户再次尝试登录时,系统检查当前时间与锁定时间的差值。如果差值小于10分钟,则拒绝登录;否则,允许登录‌。
自动解锁机制 ‌:
系统会在用户被锁定10分钟后自动解锁,允许用户重新尝试登录。
可以设置一个定时任务或使用Redis的过期功能来自动更新锁定状态‌。
用户界面提示 ‌:
当用户尝试登录时,系统应提示用户已达到登录失败次数限制,并告知用户将在10分钟后解锁。
可以设置一个倒计时提示,让用户知道还有多久可以重新尝试登录‌。

落地代码实现

user表,添加字段

相关实体对应上
RunnerGo-permission-open/internal/pkg/dal/model/user.gen.go     32
LoginFailCount int32 `gorm:"column:login_fail_count;not null" json:"login_fail_count"`
LockedTime time.Time `gorm:"column:locked_time" json:"locked_time"`


RunnerGo-permission-open/internal/pkg/dal/query/user.gen.go    45
_user.LoginFailCount = field.NewInt32(tableName, "login_fail_count")
_user.LockedTime = field.NewTime(tableName, "locked_time")


LoginFailCount field.Int32 //登录失败次数
LockedTime field.Time//锁定时间


u.LoginFailCount = field.NewInt32(table, "login_fail_count")
u.LockedTime = field.NewTime(table, "locked_time")


u.fieldMap["login_fail_count"] = u.LoginFailCount
u.fieldMap["locked_time"] = u.LockedTime

了解参考的资料

Code generated by gorm.io/gen. DO NOT EDIT

Gorm + Gen自动生成数据库结构体

Gorm + Gen自动生成数据库结构体_gorm gen-CSDN博客

核心代码实现

RunnerGo-permission-open/internal/pkg/logic/auth/auth.go       348

var loginFailCount int32 = 0


func Login(ctx *gin.Context, req rao.AuthLoginReq) (*model.User, error) {
    tx := query.Use(dal.DB()).User
    user, err := tx.WithContext(ctx).Where(tx.Account.Eq(req.Account)).First()


    if err != nil {
       return nil, errmsg.ErrAccountNotFound
    }


    loginFailCount = user.LoginFailCount
    if err := omnibus.CompareBcryptHashAndPassword(user.Password, req.Password); err != nil { //密码错误
       if loginFailCount < 5 { //0为第1次失败,4为第5次失败(数据库存的5)
          loginFailCount++
          UpdateLoginFailCount(ctx, user.UserID, loginFailCount) //更新失败次数
          if loginFailCount == 5 {
             UpdateLockedTime(ctx, user.UserID) //更新(记录)锁定起始时间
          }
          return nil, errmsg.ErrPasswordFailed
       } else {
          //如果锁定10分钟以后,解除账号锁定。如果继续输入错误密码,那么重新累加5次,再锁定10分钟
          if time.Now().Unix()-user.LockedTime.Unix() < 60 { //10分钟为600秒。60秒方便测试
             return nil, errmsg.ErrPasswordFailedFive
          } else { //解锁账号,失败次数置为0
             UpdateLoginFailCount(ctx, user.UserID, 0) //更新失败次数
             //return nil, errmsg.ErrPasswordFailed
             return nil, errmsg.ErrPasswordFailedFive
          }
       }
    } else { //密码正确
       if loginFailCount == 5 {
          //log.Logger.Errorf("10分钟倒计时开始!!!")
          //用户再次尝试登录时,系统检查当前时间与锁定时间的差值。如果差值小于10分钟,则拒绝登录;否则,允许登录‌
          if time.Now().Unix()-user.LockedTime.Unix() < 60 { //10分钟为600秒。60秒方便测试
             return nil, errmsg.ErrPasswordFailedFive
          } else {
             UpdateLoginFailCount(ctx, user.UserID, 0) //更新失败次数
             UpdateLoginTime(ctx, user.UserID)         //更新登录时间
          }
       }
    }


    uc := query.Use(dal.DB()).UserCompany
    userCompany, err := uc.WithContext(ctx).Where(uc.UserID.Eq(user.UserID)).First()
    if userCompany.Status == consts.CompanyUserStatusDisable {
       return nil, errmsg.ErrUserDisable
    }


    if req.InviteVerifyCode != "" {
       err := team.InviteLogin(ctx, req.InviteVerifyCode, user.UserID)
       if err != nil {
          return nil, err
       }
    }
    return user, nil
}


// 更新登录失败次数
func UpdateLoginFailCount(ctx context.Context, userID string, loginFailCount int32) error {
    tx := query.Use(dal.DB()).User
    _, err := tx.WithContext(ctx).Where(tx.UserID.Eq(userID)).UpdateColumn(tx.LoginFailCount, loginFailCount)
    return err
}


// 更新锁定时间
func UpdateLockedTime(ctx context.Context, userID string) error {
    tx := query.Use(dal.DB()).User
    _, err := tx.WithContext(ctx).Where(tx.UserID.Eq(userID)).UpdateColumn(tx.LockedTime, time.Now())
    return err
}


网站公告

今日签到

点亮在社区的每一天
去签到