距离第一次登陆失败次数间隔
type CommonLogin struct {
CreateTime time.Time
LastTime time.Time
Times uint8
}
正常登陆的前置校验
// 登录的前置校验
func beforeCommonLoginValid(key string, r *redis.Client, field string) (bool, error) {
// redis中是否存在账号
result, err := r.HExists(field, key).Result()
if err != nil {
fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)
return false, err
}
if result {
login := &CommonLogin{}
// 存在账号 说明之前登录失败过 且自从上次失败未登录成功过
commonLogin, err := r.HGet(field, key).Result()
if err != nil {
return false, err
}
json.Unmarshal([]byte(commonLogin), login)
if login.Times < 6 {
return true, nil
}
// 是否在1小时内失败了6次
if login.Times >= 6 {
// 否
if time.Now().Sub(login.CreateTime) > time.Hour*1 {
// 连续输错6次时长大于1小时 解锁
r.HDel(field, key)
return true, nil
} else {
fmt.Printf("用户%s于1小时之内连续登录失败6次,账号锁定,1小时后重试。", key)
return false, nil
}
}
}
// redis中不存在重试记录
return true, nil
}
此方法相当于一个切面,在进入登录逻辑之前调用即可。与此同时没有一个后置校验,来处理登录之后的成功或失败,成功则清空登录信息,失败则累加失败次数,以此来锁定账号,或者长时间登录之后解锁账号。
正常登陆的后置校验
// 登录的后置校验
func afterCommonLoginValid(key string, r *redis.Client, loginState bool) {
field := engine.Config().GetString("common_login")
result, _ := r.HExists(field, key).Result()
login := &CommonLogin{}
// 存在
if result {
// 登录失败
if !loginState {
// 更新登录失败次数和登录失败的时间
commonLogin, _ := r.HGet(field, key).Result()
json.Unmarshal([]byte(commonLogin), login)
login.Times = login.Times + 1
login.LastTime = time.Now()
data, _ := json.Marshal(login)
r.HSet(field, key, data)
} else {
r.HDel(field, key)
}
// 不存在
} else {
// 且首次登录失败
if !loginState {
login.Times = 1
login.LastTime = time.Now()
login.CreateTime = login.LastTime
data, _ := json.Marshal(login)
r.HSet(field, key, data).Result()
}
}
}
在所有的登录判断的出口,调用此方法即可,例如用户名密码错误,acl校验未通过等等。
忘记密码的登录前置校验
其实原理差不多,唯一的区别就是多了一个获取验证码时间间隔校验。
func beforeForgotPasswordValid(key string, r *redis.Client, field string) (bool, error) {
// redis中是否存在账号
result, err := r.HExists(field, key).Result()
if err != nil {
fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)
return false, err
}
login := &CommonLogin{}
// 账号存在
if result {
commonLogin, err := r.HGet(field, key).Result()
if err != nil {
return false, err
}
json.Unmarshal([]byte(commonLogin), login)
// 获取验证码间隔时长不能小于60s
if time.Now().Sub(login.LastTime) < time.Second*60 {
fmt.Printf("用户获取验证码间隔小于60s")
return false, nil
}
if login.Times < 3 {
return true, nil
}
// 是否在1小时内获取了3次
if login.Times >= 3 {
// 否
if time.Now().Sub(login.CreateTime) > time.Hour*3 {
// 连续输错6次时长大于1小时 解锁
r.HDel(field, key)
return true, nil
} else {
fmt.Printf("用户%s于3小时之内连续获取验证码3次,账号锁定,3小时后重试。", key)
return false, nil
}
}
}
return true, nil
}
忘记密码的后置校验
// 更新获取验证码的时间
func afterForgotPasswordValid(key string, r *redis.Client, field string) {
login := &CommonLogin{}
commonLogin, _ := r.HGet(field, key).Result()
json.Unmarshal([]byte(commonLogin), login)
// 验证码发送成功
result, _ := r.HExists(field, key).Result()
if result {
login.Times = login.Times + 1
login.LastTime = time.Now()
data, _ := json.Marshal(login)
r.HSet(field, key, data)
} else {
login.Times = 1
login.LastTime = time.Now()
login.CreateTime = login.LastTime
data, _ := json.Marshal(login)
r.HSet(field, key, data)
}
}