feat: allow captcha to be enabled when logging in (#1211)

* Fix bug in GetAcceptLanguage()

* feat: allow captcha to be enabled when logging in

* feat: when the login password is wrong, enable captcha

* feat: Restrict captcha from frontend

* fix: modify CaptchaModal component

* fix: modify the words of i18n

* Update data.json

Co-authored-by: Gucheng Wang <nomeguy@qq.com>
Co-authored-by: hsluoyz <hsluoyz@qq.com>
This commit is contained in:
wenxuan70
2022-10-28 13:38:14 +08:00
committed by GitHub
parent 7e5952c804
commit 25d56ee8d5
19 changed files with 373 additions and 114 deletions

View File

@ -29,6 +29,7 @@ import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput";
import SelectLanguageBox from "../SelectLanguageBox";
import {withTranslation} from "react-i18next";
import {CaptchaModal} from "../common/CaptchaModal";
const {TabPane} = Tabs;
@ -48,6 +49,9 @@ class LoginPage extends React.Component {
validEmail: false,
validPhone: false,
loginMethod: "password",
enableCaptchaModal: false,
openCaptchaModal: false,
verifyCaptcha: undefined,
};
if (this.state.type === "cas" && props.match?.params.casApplicationName !== undefined) {
@ -68,6 +72,18 @@ class LoginPage extends React.Component {
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.state.application && !prevState.application) {
const defaultCaptchaProviderItems = this.getDefaultCaptchaProviderItems(this.state.application);
if (!defaultCaptchaProviderItems) {
return;
}
this.setState({enableCaptchaModal: defaultCaptchaProviderItems.some(providerItem => providerItem.rule === "Always")});
}
}
getApplicationLogin() {
const oAuthParams = Util.getOAuthGetParameters();
AuthBackend.getApplicationLogin(oAuthParams)
@ -225,6 +241,23 @@ class LoginPage extends React.Component {
return;
}
if (this.state.loginMethod === "password" && this.state.enableCaptchaModal) {
this.setState({
openCaptchaModal: true,
verifyCaptcha: (captchaType, captchaToken, secret) => {
values["captchaType"] = captchaType;
values["captchaToken"] = captchaToken;
values["clientSecret"] = secret;
this.login(values);
},
});
} else {
this.login(values);
}
}
login(values) {
// here we are supposed to determine whether Casdoor is working as an OAuth server or CAS server
if (this.state.type === "cas") {
// CAS
@ -239,6 +272,8 @@ class LoginPage extends React.Component {
}
Util.showMessage("success", msg);
this.setState({openCaptchaModal: false});
if (casParams.service !== "") {
const st = res.data;
const newUrl = new URL(casParams.service);
@ -246,6 +281,7 @@ class LoginPage extends React.Component {
window.location.href = newUrl.toString();
}
} else {
this.setState({openCaptchaModal: false});
Util.showMessage("error", `Failed to log in: ${res.msg}`);
}
});
@ -258,6 +294,7 @@ class LoginPage extends React.Component {
.then((res) => {
if (res.status === "ok") {
const responseType = values["type"];
if (responseType === "login") {
Util.showMessage("success", "Logged in successfully");
@ -275,6 +312,7 @@ class LoginPage extends React.Component {
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);
}
} else {
this.setState({openCaptchaModal: false});
Util.showMessage("error", `Failed to log in: ${res.msg}`);
}
});
@ -418,6 +456,9 @@ class LoginPage extends React.Component {
i18next.t("login:Sign In")
}
</Button>
{
this.renderCaptchaModal(application)
}
{
this.renderFooter(application)
}
@ -460,6 +501,46 @@ class LoginPage extends React.Component {
}
}
getDefaultCaptchaProviderItems(application) {
const providers = application?.providers;
if (providers === undefined || providers === null) {
return null;
}
return providers.filter(providerItem => {
if (providerItem.provider === undefined || providerItem.provider === null) {
return false;
}
return providerItem.provider.category === "Captcha" && providerItem.provider.type === "Default";
});
}
renderCaptchaModal(application) {
if (!this.state.enableCaptchaModal) {
return null;
}
const provider = this.getDefaultCaptchaProviderItems(application)
.filter(providerItem => providerItem.rule === "Always")
.map(providerItem => providerItem.provider)[0];
return <CaptchaModal
owner={provider.owner}
name={provider.name}
captchaType={provider.type}
subType={provider.subType}
clientId={provider.clientId}
clientId2={provider.clientId2}
clientSecret={provider.clientSecret}
clientSecret2={provider.clientSecret2}
open={this.state.openCaptchaModal}
onOk={(captchaType, captchaToken, secret) => this.state.verifyCaptcha?.(captchaType, captchaToken, secret)}
canCancel={false}
/>;
}
renderFooter(application) {
if (this.state.mode === "signup") {
return (