mirror of
https://github.com/casdoor/casdoor.git
synced 2025-09-06 01:40:27 +08:00
feat: support inline-captcha in login page (#3970)
This commit is contained in:
@@ -437,6 +437,9 @@ class LoginPage extends React.Component {
|
||||
values["password"] = passwordCipher;
|
||||
}
|
||||
const captchaRule = this.getCaptchaRule(this.getApplicationObj());
|
||||
const application = this.getApplicationObj();
|
||||
const noModal = application?.signinItems.map(signinItem => signinItem.name === "Captcha" && signinItem.rule === "inline").includes(true);
|
||||
if (!noModal) {
|
||||
if (captchaRule === CaptchaRule.Always) {
|
||||
this.setState({
|
||||
openCaptchaModal: true,
|
||||
@@ -450,6 +453,11 @@ class LoginPage extends React.Component {
|
||||
this.checkCaptchaStatus(values);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
values["captchaType"] = this.state?.captchaValues?.captchaType;
|
||||
values["captchaToken"] = this.state?.captchaValues?.captchaToken;
|
||||
values["clientSecret"] = this.state?.captchaValues?.clientSecret;
|
||||
}
|
||||
}
|
||||
this.login(values);
|
||||
}
|
||||
@@ -775,7 +783,7 @@ class LoginPage extends React.Component {
|
||||
</>
|
||||
}
|
||||
{
|
||||
this.renderCaptchaModal(application)
|
||||
application?.signinItems.map(signinItem => signinItem.name === "Captcha" && signinItem.rule === "inline").includes(true) ? null : this.renderCaptchaModal(application, false)
|
||||
}
|
||||
</Form.Item>
|
||||
);
|
||||
@@ -819,6 +827,8 @@ class LoginPage extends React.Component {
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
} else if (signinItem.name === "Captcha" && signinItem.rule === "inline") {
|
||||
return this.renderCaptchaModal(application, true);
|
||||
} else if (signinItem.name.startsWith("Text ") || signinItem?.isCustom) {
|
||||
return (
|
||||
<div key={resultItemKey} dangerouslySetInnerHTML={{__html: signinItem.customCss}} />
|
||||
@@ -964,7 +974,7 @@ class LoginPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
renderCaptchaModal(application) {
|
||||
renderCaptchaModal(application, noModal) {
|
||||
if (this.getCaptchaRule(this.getApplicationObj()) === CaptchaRule.Never) {
|
||||
return null;
|
||||
}
|
||||
@@ -993,6 +1003,12 @@ class LoginPage extends React.Component {
|
||||
owner={provider.owner}
|
||||
name={provider.name}
|
||||
visible={this.state.openCaptchaModal}
|
||||
noModal={noModal}
|
||||
onUpdateToken={(captchaType, captchaToken, clientSecret) => {
|
||||
this.setState({captchaValues: {
|
||||
captchaType, captchaToken, clientSecret,
|
||||
}});
|
||||
}}
|
||||
onOk={(captchaType, captchaToken, clientSecret) => {
|
||||
const values = this.state.values;
|
||||
values["captchaType"] = captchaType;
|
||||
|
@@ -20,7 +20,7 @@ import {CaptchaWidget} from "../CaptchaWidget";
|
||||
import {SafetyOutlined} from "@ant-design/icons";
|
||||
|
||||
export const CaptchaModal = (props) => {
|
||||
const {owner, name, visible, onOk, onCancel, isCurrentProvider} = props;
|
||||
const {owner, name, visible, onOk, onUpdateToken, onCancel, isCurrentProvider, noModal} = props;
|
||||
|
||||
const [captchaType, setCaptchaType] = React.useState("none");
|
||||
const [clientId, setClientId] = React.useState("");
|
||||
@@ -36,16 +36,16 @@ export const CaptchaModal = (props) => {
|
||||
const defaultInputRef = React.useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
if (visible || noModal) {
|
||||
loadCaptcha();
|
||||
} else {
|
||||
handleCancel();
|
||||
setOpen(false);
|
||||
}
|
||||
}, [visible]);
|
||||
}, [visible, noModal]);
|
||||
|
||||
useEffect(() => {
|
||||
if (captchaToken !== "" && captchaType !== "Default") {
|
||||
if (captchaToken !== "" && captchaType !== "Default" && !noModal) {
|
||||
handleOk();
|
||||
}
|
||||
}, [captchaToken]);
|
||||
@@ -81,6 +81,36 @@ export const CaptchaModal = (props) => {
|
||||
};
|
||||
|
||||
const renderDefaultCaptcha = () => {
|
||||
if (noModal) {
|
||||
return (
|
||||
<Row style={{textAlign: "center"}}>
|
||||
<Col
|
||||
style={{flex: noModal ? "70%" : "100%"}}>
|
||||
<Input
|
||||
ref={defaultInputRef}
|
||||
value={captchaToken}
|
||||
prefix={<SafetyOutlined />}
|
||||
placeholder={i18next.t("general:Captcha")}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
style={{
|
||||
flex: noModal ? "30%" : "100%",
|
||||
}}
|
||||
>
|
||||
<img src={`data:image/png;base64,${captchaImg}`}
|
||||
onClick={loadCaptcha}
|
||||
style={{
|
||||
borderRadius: "5px",
|
||||
border: "1px solid #ccc",
|
||||
marginBottom: "20px",
|
||||
width: "100%",
|
||||
}} alt="captcha" />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Col style={{textAlign: "center"}}>
|
||||
<div style={{display: "inline-block"}}>
|
||||
@@ -113,6 +143,9 @@ export const CaptchaModal = (props) => {
|
||||
|
||||
const onChange = (token) => {
|
||||
setCaptchaToken(token);
|
||||
if (noModal) {
|
||||
onUpdateToken?.(captchaType, token, clientSecret);
|
||||
}
|
||||
};
|
||||
|
||||
const renderCaptcha = () => {
|
||||
@@ -153,6 +186,10 @@ export const CaptchaModal = (props) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
if (noModal) {
|
||||
return renderCaptcha();
|
||||
|
||||
} else {
|
||||
return (
|
||||
<Modal
|
||||
closable={true}
|
||||
@@ -175,6 +212,7 @@ export const CaptchaModal = (props) => {
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const CaptchaRule = {
|
||||
|
@@ -49,6 +49,9 @@ class SigninTable extends React.Component {
|
||||
|
||||
updateField(table, index, key, value) {
|
||||
table[index][key] = value;
|
||||
if (key === "name" && value === "Captcha") {
|
||||
table[index]["rule"] = "pop up";
|
||||
}
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
@@ -114,6 +117,7 @@ class SigninTable extends React.Component {
|
||||
{name: "Forgot password?", displayName: i18next.t("login:Forgot password?")},
|
||||
{name: "Login button", displayName: i18next.t("login:Signin button")},
|
||||
{name: "Signup link", displayName: i18next.t("general:Signup link")},
|
||||
{name: "Captcha", displayName: i18next.t("general:Captcha")},
|
||||
];
|
||||
|
||||
const getItemDisplayName = (text) => {
|
||||
@@ -249,6 +253,12 @@ class SigninTable extends React.Component {
|
||||
{id: "small", name: i18next.t("application:Small icon")},
|
||||
];
|
||||
}
|
||||
if (record.name === "Captcha") {
|
||||
options = [
|
||||
{id: "pop up", name: i18next.t("application:Pop up")},
|
||||
{id: "inline", name: i18next.t("application:Inline")},
|
||||
];
|
||||
}
|
||||
if (options.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user