From 2819e3a1d10f3c556a92adb0ca3fb0746034d9d3 Mon Sep 17 00:00:00 2001 From: CaIon Date: Sun, 12 Apr 2026 17:11:20 +0800 Subject: [PATCH] fix: improve login error handling to distinguish database errors from auth failures ValidateAndFill now checks the DB query result and returns sentinel errors (ErrDatabase, ErrInvalidCredentials, ErrUserEmptyCredentials) instead of hardcoded Chinese strings. The controller maps each sentinel to the appropriate i18n message, so users see "please contact admin" on DB errors instead of a misleading "wrong password" message. Non-DB errors still return a unified vague response to avoid leaking user existence. --- controller/user.go | 13 +++++++++---- i18n/locales/en.yaml | 2 +- i18n/locales/zh-CN.yaml | 2 +- i18n/locales/zh-TW.yaml | 2 +- model/user.go | 20 ++++++++++++++++---- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/controller/user.go b/controller/user.go index 8e26320f..7921e337 100644 --- a/controller/user.go +++ b/controller/user.go @@ -52,10 +52,15 @@ func Login(c *gin.Context) { } err = user.ValidateAndFill() if err != nil { - c.JSON(http.StatusOK, gin.H{ - "message": err.Error(), - "success": false, - }) + switch { + case errors.Is(err, model.ErrDatabase): + common.SysLog(fmt.Sprintf("Login database error for user %s: %v", username, err)) + common.ApiErrorI18n(c, i18n.MsgDatabaseError) + case errors.Is(err, model.ErrUserEmptyCredentials): + common.ApiErrorI18n(c, i18n.MsgInvalidParams) + default: + common.ApiErrorI18n(c, i18n.MsgUserUsernameOrPasswordError) + } return } diff --git a/i18n/locales/en.yaml b/i18n/locales/en.yaml index 3cb9ac2c..5618a782 100644 --- a/i18n/locales/en.yaml +++ b/i18n/locales/en.yaml @@ -2,7 +2,7 @@ # Common messages common.invalid_params: "Invalid parameters" -common.database_error: "Database error, please try again later" +common.database_error: "Database error, please contact the administrator" common.retry_later: "Please try again later" common.generate_failed: "Generation failed" common.not_found: "Not found" diff --git a/i18n/locales/zh-CN.yaml b/i18n/locales/zh-CN.yaml index 20f8a77b..e4f1fac1 100644 --- a/i18n/locales/zh-CN.yaml +++ b/i18n/locales/zh-CN.yaml @@ -3,7 +3,7 @@ # Common messages common.invalid_params: "无效的参数" -common.database_error: "数据库错误,请稍后重试" +common.database_error: "数据库出错,请联系管理员" common.retry_later: "请稍后重试" common.generate_failed: "生成失败" common.not_found: "未找到" diff --git a/i18n/locales/zh-TW.yaml b/i18n/locales/zh-TW.yaml index 887322c2..854cd111 100644 --- a/i18n/locales/zh-TW.yaml +++ b/i18n/locales/zh-TW.yaml @@ -3,7 +3,7 @@ # Common messages common.invalid_params: "無效的參數" -common.database_error: "資料庫錯誤,請稍後重試" +common.database_error: "資料庫出錯,請聯繫管理員" common.retry_later: "請稍後重試" common.generate_failed: "生成失敗" common.not_found: "未找到" diff --git a/model/user.go b/model/user.go index 2bd1a8c3..9ff2a15f 100644 --- a/model/user.go +++ b/model/user.go @@ -18,6 +18,12 @@ import ( const UserNameMaxLength = 20 +var ( + ErrDatabase = errors.New("database error") + ErrInvalidCredentials = errors.New("invalid credentials") + ErrUserEmptyCredentials = errors.New("empty credentials") +) + // User if you add sensitive fields, don't forget to clean them in setupLogin function. // Otherwise, the sensitive information will be saved on local storage in plain text! type User struct { @@ -597,13 +603,19 @@ func (user *User) ValidateAndFill() (err error) { password := user.Password username := strings.TrimSpace(user.Username) if username == "" || password == "" { - return errors.New("用户名或密码为空") + return ErrUserEmptyCredentials + } + // find by username or email + err = DB.Where("username = ? OR email = ?", username, username).First(user).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrInvalidCredentials + } + return fmt.Errorf("%w: %v", ErrDatabase, err) } - // find buy username or email - DB.Where("username = ? OR email = ?", username, username).First(user) okay := common.ValidatePasswordAndHash(password, user.Password) if !okay || user.Status != common.UserStatusEnabled { - return errors.New("用户名或密码错误,或用户已被封禁") + return ErrInvalidCredentials } return nil }