fix: fallback to password login when mfa needs captcha (#12438)

This commit is contained in:
ssongliu
2026-04-09 10:28:39 +08:00
committed by GitHub
parent 75be8d3a23
commit 218f92a960
4 changed files with 24 additions and 7 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/1Panel-dev/1Panel/core/buserr"
"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/global"
initauth "github.com/1Panel-dev/1Panel/core/init/auth"
"github.com/1Panel-dev/1Panel/core/utils/captcha"
"github.com/1Panel-dev/1Panel/core/utils/common"
"github.com/gin-gonic/gin"
@@ -109,6 +110,12 @@ func (b *BaseApi) MFALogin(c *gin.Context) {
go saveLoginLogs(c, wrapLoginErr(msgKey, err))
if msgKey == "ErrMFA" {
global.IPTracker.RecordFailure(ip)
failures := initauth.GetMFASessionStore().RecordFailure(req.SessionID)
if failures >= initauth.MFASessionMaxFailures {
global.IPTracker.SetNeedCaptcha(ip)
helper.BadAuth(c, "ErrCaptchaCode", nil)
return
}
helper.BadAuth(c, msgKey, err)
return
}

View File

@@ -114,7 +114,6 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
}
success := mfa.ValidCode(info.Code, mfaInterval.Value, mfaSecret.Value)
if !success {
mfaSessions.RecordFailure(info.SessionID)
return nil, "ErrMFA", nil
}
res, err := u.generateSession(c, session.Name)

View File

@@ -76,27 +76,27 @@ func (s *mfaSessionStore) Delete(sessionID string) {
delete(s.items, sessionID)
}
func (s *mfaSessionStore) RecordFailure(sessionID string) bool {
func (s *mfaSessionStore) RecordFailure(sessionID string) int {
s.mu.Lock()
defer s.mu.Unlock()
item, ok := s.items[sessionID]
if !ok {
return false
return 0
}
if time.Now().After(item.ExpiresAt) {
delete(s.items, sessionID)
return false
return 0
}
item.Failures++
if item.Failures >= MFASessionMaxFailures {
delete(s.items, sessionID)
return false
return item.Failures
}
s.items[sessionID] = item
return true
return item.Failures
}
func (s *mfaSessionStore) cleanupExpiredLocked() {

View File

@@ -437,6 +437,7 @@ const login = (formEl: FormInstance | undefined) => {
mfaLoginForm.code = '';
mfaShow.value = true;
errMfaInfo.value = false;
errCaptcha.value = false;
nextTick(() => {
mfaLoginRef.value?.focus();
});
@@ -485,6 +486,7 @@ const mfaLogin = async (auto: boolean) => {
if ((!auto && mfaLoginForm.code) || (auto && mfaLoginForm.code.length === 6)) {
isLoggingIn = true;
try {
errMfaInfo.value = false;
await mfaLoginApi(mfaLoginForm);
globalStore.setLogStatus(true);
menuStore.setMenuList([]);
@@ -498,7 +500,15 @@ const mfaLogin = async (auto: boolean) => {
document.onkeydown = null;
} catch (res) {
if (res.code === 401) {
if (res.message === 'ErrMFA') {
if (res.message === 'ErrCaptchaCode') {
globalStore.ignoreCaptcha = false;
mfaLoginForm.code = '';
mfaShow.value = false;
loginVerify();
nextTick(() => {
userNameRef.value?.focus();
});
} else if (res.message === 'ErrMFA') {
errMfaInfo.value = true;
} else if (res.message) {
MsgError(res.message);
@@ -506,6 +516,7 @@ const mfaLogin = async (auto: boolean) => {
isLoggingIn = false;
return;
}
loginVerify();
} finally {
isLoggingIn = false;
}