mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 10:45:47 +08:00
feat(login): add login limit (#1023)
* feat(login): add login limit * chore: rename vars * chore: use `string` * fix: clear the signin error times after succeessfull login * chore: modify code position
This commit is contained in:
parent
70f2988f09
commit
aedef1eea1
@ -18,6 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/cred"
|
"github.com/casdoor/casdoor/cred"
|
||||||
@ -30,6 +31,11 @@ var (
|
|||||||
reFieldWhiteList *regexp.Regexp
|
reFieldWhiteList *regexp.Regexp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SigninWrongTimesLimit = 5
|
||||||
|
LastSignWrongTimeDuration = time.Minute * 15
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
reWhiteSpace, _ = regexp.Compile(`\s`)
|
reWhiteSpace, _ = regexp.Compile(`\s`)
|
||||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||||
@ -127,7 +133,32 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkSigninErrorTimes(user *User) string {
|
||||||
|
if user.SigninWrongTimes >= SigninWrongTimesLimit {
|
||||||
|
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
|
||||||
|
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
|
||||||
|
seconds := int(LastSignWrongTimeDuration.Seconds() - passedTime.Seconds())
|
||||||
|
|
||||||
|
// deny the login if the error times is greater than the limit and the last login time is less than the duration
|
||||||
|
if seconds > 0 {
|
||||||
|
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", seconds/60, seconds%60)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the error times
|
||||||
|
user.SigninWrongTimes = 0
|
||||||
|
|
||||||
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, user.IsGlobalAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func CheckPassword(user *User, password string) string {
|
func CheckPassword(user *User, password string) string {
|
||||||
|
// check the login error times
|
||||||
|
if msg := checkSigninErrorTimes(user); msg != "" {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
organization := GetOrganizationByUser(user)
|
organization := GetOrganizationByUser(user)
|
||||||
if organization == nil {
|
if organization == nil {
|
||||||
return "organization does not exist"
|
return "organization does not exist"
|
||||||
@ -137,14 +168,17 @@ func CheckPassword(user *User, password string) string {
|
|||||||
if credManager != nil {
|
if credManager != nil {
|
||||||
if organization.MasterPassword != "" {
|
if organization.MasterPassword != "" {
|
||||||
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
|
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
|
||||||
|
resetUserSigninErrorTimes(user)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if credManager.IsPasswordCorrect(password, user.Password, user.PasswordSalt, organization.PasswordSalt) {
|
if credManager.IsPasswordCorrect(password, user.Password, user.PasswordSalt, organization.PasswordSalt) {
|
||||||
|
resetUserSigninErrorTimes(user)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return "password incorrect"
|
|
||||||
|
return recordSigninErrorInfo(user)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("unsupported password type: %s", organization.PasswordType)
|
return fmt.Sprintf("unsupported password type: %s", organization.PasswordType)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
|
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import "regexp"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
var reRealName *regexp.Regexp
|
var reRealName *regexp.Regexp
|
||||||
|
|
||||||
@ -29,3 +33,32 @@ func init() {
|
|||||||
func isValidRealName(s string) bool {
|
func isValidRealName(s string) bool {
|
||||||
return reRealName.MatchString(s)
|
return reRealName.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resetUserSigninErrorTimes(user *User) {
|
||||||
|
// if the password is correct and wrong times is not zero, reset the error times
|
||||||
|
if user.SigninWrongTimes == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user.SigninWrongTimes = 0
|
||||||
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordSigninErrorInfo(user *User) string {
|
||||||
|
// increase failed login count
|
||||||
|
user.SigninWrongTimes++
|
||||||
|
|
||||||
|
if user.SigninWrongTimes >= SigninWrongTimesLimit {
|
||||||
|
// record the latest failed login time
|
||||||
|
user.LastSigninWrongTime = time.Now().UTC().Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update user
|
||||||
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
||||||
|
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
|
||||||
|
if leftChances > 0 {
|
||||||
|
return fmt.Sprintf("password is incorrect, you have %d remaining chances", leftChances)
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't show the chance error message if the user has no chance left
|
||||||
|
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes and try again", int(LastSignWrongTimeDuration.Minutes()))
|
||||||
|
}
|
||||||
|
@ -111,6 +111,9 @@ type User struct {
|
|||||||
|
|
||||||
Roles []*Role `json:"roles"`
|
Roles []*Role `json:"roles"`
|
||||||
Permissions []*Permission `json:"permissions"`
|
Permissions []*Permission `json:"permissions"`
|
||||||
|
|
||||||
|
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||||
|
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Userinfo struct {
|
type Userinfo struct {
|
||||||
@ -376,6 +379,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
|||||||
"owner", "display_name", "avatar",
|
"owner", "display_name", "avatar",
|
||||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials",
|
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials",
|
||||||
|
"signin_wrong_times", "last_signin_wrong_time",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isGlobalAdmin {
|
if isGlobalAdmin {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user