mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-17 04:03:23 +08:00

* feat: allow user use other mfaType in mfa step and skip redundant MFA verification * feat: improve format
140 lines
4.7 KiB
JavaScript
140 lines
4.7 KiB
JavaScript
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import React, {Fragment, useState} from "react";
|
|
import i18next from "i18next";
|
|
import {Button, Input} from "antd";
|
|
import * as AuthBackend from "../AuthBackend";
|
|
import {EmailMfaType, RecoveryMfaType, SmsMfaType} from "../MfaSetupPage";
|
|
import {mfaAuth} from "./MfaVerifyForm";
|
|
import MfaVerifySmsForm from "./MfaVerifySmsForm";
|
|
import MfaVerifyTotpForm from "./MfaVerifyTotpForm";
|
|
|
|
export const NextMfa = "NextMfa";
|
|
export const RequiredMfa = "RequiredMfa";
|
|
|
|
export function MfaAuthVerifyForm({formValues, authParams, mfaProps, application, onSuccess, onFail}) {
|
|
formValues.password = "";
|
|
formValues.username = "";
|
|
const [loading, setLoading] = useState(false);
|
|
const [mfaType, setMfaType] = useState(mfaProps.mfaType);
|
|
const [recoveryCode, setRecoveryCode] = useState("");
|
|
|
|
const verify = ({passcode}) => {
|
|
setLoading(true);
|
|
const values = {...formValues, passcode};
|
|
values["mfaType"] = mfaProps.mfaType;
|
|
const loginFunction = formValues.type === "cas" ? AuthBackend.loginCas : AuthBackend.login;
|
|
loginFunction(values, authParams).then((res) => {
|
|
if (res.status === "ok") {
|
|
onSuccess(res);
|
|
} else {
|
|
onFail(res.msg);
|
|
}
|
|
}).catch((res) => {
|
|
onFail(res.message);
|
|
}).finally(() => {
|
|
setLoading(false);
|
|
});
|
|
};
|
|
|
|
const recover = () => {
|
|
setLoading(true);
|
|
const values = {...formValues, recoveryCode};
|
|
const loginFunction = formValues.type === "cas" ? AuthBackend.loginCas : AuthBackend.login;
|
|
loginFunction(values, authParams).then((res) => {
|
|
if (res.status === "ok") {
|
|
onSuccess(res);
|
|
} else {
|
|
onFail(res.msg);
|
|
}
|
|
}).catch((res) => {
|
|
onFail(res.message);
|
|
}).finally(() => {
|
|
setLoading(false);
|
|
});
|
|
};
|
|
|
|
if (mfaType !== RecoveryMfaType) {
|
|
return (
|
|
<div style={{width: 320, height: 350}}>
|
|
<div style={{marginBottom: 24, textAlign: "center", fontSize: "24px"}}>
|
|
{i18next.t("mfa:Multi-factor authentication")}
|
|
</div>
|
|
{mfaProps.mfaType === SmsMfaType || mfaProps.mfaType === EmailMfaType ? (
|
|
<Fragment>
|
|
<div style={{marginBottom: 24}}>
|
|
{i18next.t("mfa:You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue")}
|
|
</div>
|
|
<MfaVerifySmsForm
|
|
mfaProps={mfaProps}
|
|
method={mfaAuth}
|
|
onFinish={verify}
|
|
application={application}
|
|
/>
|
|
</Fragment>
|
|
) : (
|
|
<Fragment>
|
|
<div style={{marginBottom: 24}}>
|
|
{i18next.t("mfa:You have enabled Multi-Factor Authentication, please enter the TOTP code")}
|
|
</div>
|
|
<MfaVerifyTotpForm
|
|
mfaProps={mfaProps}
|
|
onFinish={verify}
|
|
/>
|
|
</Fragment>
|
|
)}
|
|
<span style={{float: "right"}}>
|
|
{i18next.t("mfa:Have problems?")}
|
|
<a onClick={() => {
|
|
setMfaType("recovery");
|
|
}}>
|
|
{i18next.t("mfa:Use a recovery code")}
|
|
</a>
|
|
</span>
|
|
</div>
|
|
);
|
|
} else {
|
|
return (
|
|
<div style={{width: 300, height: 350}}>
|
|
<div style={{marginBottom: 24, textAlign: "center", fontSize: "24px"}}>
|
|
{i18next.t("mfa:Multi-factor recover")}
|
|
</div>
|
|
<div style={{marginBottom: 24}}>
|
|
{i18next.t("mfa:Multi-factor recover description")}
|
|
</div>
|
|
<Input placeholder={i18next.t("mfa:Recovery code")}
|
|
style={{marginBottom: 24}}
|
|
type={"passcode"}
|
|
size={"large"}
|
|
onChange={event => setRecoveryCode(event.target.value)}
|
|
/>
|
|
<Button style={{width: "100%", marginBottom: 20}} size={"large"} loading={loading}
|
|
type={"primary"} onClick={() => {
|
|
recover();
|
|
}}>{i18next.t("forget:Verify")}
|
|
</Button>
|
|
<span style={{float: "right"}}>
|
|
{i18next.t("mfa:Have problems?")}
|
|
<a onClick={() => {
|
|
setMfaType(mfaProps.mfaType);
|
|
}}>
|
|
{i18next.t("mfa:Use SMS verification code")}
|
|
</a>
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
}
|