diff --git a/web/src/auth/LoginPage.js b/web/src/auth/LoginPage.js index f91a330c..32c50af8 100644 --- a/web/src/auth/LoginPage.js +++ b/web/src/auth/LoginPage.js @@ -46,6 +46,7 @@ const FaceRecognitionModal = lazy(() => import("../common/modal/FaceRecognitionM class LoginPage extends React.Component { constructor(props) { super(props); + this.captchaRef = React.createRef(); this.state = { classes: props, type: props.type, @@ -466,6 +467,7 @@ class LoginPage extends React.Component { login(values) { // here we are supposed to determine whether Casdoor is working as an OAuth server or CAS server values["language"] = this.state.userLang ?? ""; + const usedCaptcha = this.state.captchaValues !== undefined; if (this.state.type === "cas") { // CAS const casParams = Util.getCasParameters(); @@ -492,6 +494,9 @@ class LoginPage extends React.Component { Setting.checkLoginMfa(res, values, casParams, loginHandler, this); } else { Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`); + if (usedCaptcha) { + this.captchaRef.current?.loadCaptcha?.(); + } } }).finally(() => { this.setState({loginLoading: false}); @@ -565,6 +570,9 @@ class LoginPage extends React.Component { Setting.checkLoginMfa(res, values, oAuthParams, loginHandler, this); } else { Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`); + if (usedCaptcha) { + this.captchaRef.current?.loadCaptcha?.(); + } } }).finally(() => { this.setState({loginLoading: false}); @@ -1124,6 +1132,7 @@ class LoginPage extends React.Component { }} onCancel={() => this.setState({openCaptchaModal: false, loginLoading: false})} isCurrentProvider={true} + innerRef={this.captchaRef} />; } diff --git a/web/src/common/modal/CaptchaModal.js b/web/src/common/modal/CaptchaModal.js index bb88da91..89aa3702 100644 --- a/web/src/common/modal/CaptchaModal.js +++ b/web/src/common/modal/CaptchaModal.js @@ -20,7 +20,7 @@ import {CaptchaWidget} from "../CaptchaWidget"; import {SafetyOutlined} from "@ant-design/icons"; export const CaptchaModal = (props) => { - const {owner, name, visible, onOk, onUpdateToken, onCancel, isCurrentProvider, noModal} = props; + const {owner, name, visible, onOk, onUpdateToken, onCancel, isCurrentProvider, noModal, innerRef} = props; const [captchaType, setCaptchaType] = React.useState("none"); const [clientId, setClientId] = React.useState(""); @@ -59,6 +59,14 @@ export const CaptchaModal = (props) => { onCancel?.(); }; + useEffect(() => { + if (innerRef) { + innerRef.current = { + loadCaptcha: loadCaptcha, + }; + } + }, [innerRef]); + const loadCaptcha = () => { UserBackend.getCaptcha(owner, name, isCurrentProvider).then((res) => { if (res.type === "none") {