212 lines
4.9 KiB
Vue
212 lines
4.9 KiB
Vue
<template>
|
||
<div>
|
||
<div
|
||
class="mt-6 flex items-center justify-center"
|
||
v-if="$resources.qrUrl.loading"
|
||
>
|
||
<LoadingText />
|
||
</div>
|
||
<div
|
||
v-else-if="is2FAEnabled && $route.name !== 'Enable2FA'"
|
||
class="space-y-4"
|
||
>
|
||
<AlertBanner
|
||
title="如果禁用双重认证,您的账户将变得不安全"
|
||
type="error"
|
||
/>
|
||
|
||
<!-- 用户需要遵循的步骤 -->
|
||
<div class="rounded border border-gray-200 bg-gray-50 p-4">
|
||
<h3 class="text-lg font-semibold">禁用双重认证的步骤</h3>
|
||
<ol class="mt-2 list-disc pl-2 text-sm">
|
||
<li>打开认证器应用</li>
|
||
<li>在下方输入应用中的代码</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<FormControl
|
||
label="验证应用中的代码以禁用双重认证"
|
||
v-model="totpCode"
|
||
/>
|
||
</div>
|
||
|
||
<div v-else class="space-y-4">
|
||
<div class="w-full">
|
||
<VueQrcode
|
||
v-if="qrUrl"
|
||
class="mx-auto"
|
||
:value="qrUrl"
|
||
type="image/png"
|
||
:color="{ dark: '#000000ff', light: '#ffffffff' }"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 用户需要遵循的步骤 -->
|
||
<div class="rounded border border-gray-200 bg-gray-50 p-4">
|
||
<h3 class="text-lg font-semibold">启用双重认证的步骤</h3>
|
||
<ol class="ml-1 mt-2 list-disc pl-2 text-sm text-gray-700">
|
||
<li>在手机上下载认证器应用,例如阿里云APP等。</li>
|
||
<li>扫描二维码</li>
|
||
<li>在下方输入认证器应用中的代码</li>
|
||
</ol>
|
||
<p class="mt-4 text-sm text-gray-700">
|
||
<strong>注意:</strong> 如果您无法访问认证器应用,您的账户将被锁定。请确保备份您的保险库/密钥。
|
||
</p>
|
||
</div>
|
||
|
||
<div
|
||
v-if="showSetupKey"
|
||
class="rounded border border-gray-200 bg-gray-50 p-4"
|
||
>
|
||
<h3 class="text-lg font-semibold">设置密钥</h3>
|
||
<p class="mt-2 text-sm">
|
||
{{ setupKey }}
|
||
</p>
|
||
</div>
|
||
|
||
<FormControl
|
||
label="验证应用中的代码以启用双重认证"
|
||
v-model="totpCode"
|
||
/>
|
||
</div>
|
||
|
||
<div class="!mt-8 flex justify-center">
|
||
<Button
|
||
v-if="!is2FAEnabled"
|
||
class="w-full"
|
||
variant="solid"
|
||
label="启用双重认证"
|
||
:disabled="!totpCode"
|
||
:loading="$resources.enable2FA.loading"
|
||
@click="enable2FA"
|
||
/>
|
||
<Button
|
||
v-else
|
||
class="w-full"
|
||
variant="solid"
|
||
label="禁用双重认证"
|
||
:disabled="!totpCode"
|
||
:loading="$resources.disable2FA.loading"
|
||
@click="disable2FA"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import VueQrcode from 'vue-qrcode';
|
||
import { toast } from 'vue-sonner';
|
||
import AlertBanner from '../AlertBanner.vue';
|
||
|
||
export default {
|
||
emits: ['enabled', 'disabled'],
|
||
data() {
|
||
return {
|
||
qrUrl: '', // not storing as computed property to avoid re-fetching on dialog close
|
||
totpCode: '',
|
||
showSetupKey: false
|
||
};
|
||
},
|
||
components: {
|
||
AlertBanner,
|
||
VueQrcode
|
||
},
|
||
methods: {
|
||
enable2FA() {
|
||
toast.promise(
|
||
this.$resources.enable2FA.submit({
|
||
totp_code: this.totpCode
|
||
}),
|
||
{
|
||
loading: '正在启用双因素认证...',
|
||
success: () => {
|
||
this.totpCode = '';
|
||
|
||
// avoid flickering of 2FA dialog
|
||
setTimeout(() => {
|
||
this.$team.reload();
|
||
}, 500);
|
||
this.$emit('enabled');
|
||
|
||
return '双因素认证已成功启用';
|
||
},
|
||
error(err) {
|
||
if (err.messages) {
|
||
if (err.messages.includes('Invalid TOTP code')) {
|
||
return '无效的TOTP验证码,请重试';
|
||
} else {
|
||
return err.messages.join('.');
|
||
}
|
||
} else {
|
||
return '启用双因素认证失败';
|
||
}
|
||
}
|
||
}
|
||
);
|
||
},
|
||
disable2FA() {
|
||
toast.promise(
|
||
this.$resources.disable2FA.submit({
|
||
totp_code: this.totpCode
|
||
}),
|
||
{
|
||
loading: '正在禁用双因素认证...',
|
||
success: () => {
|
||
this.totpCode = '';
|
||
|
||
// avoid flickering of 2FA dialog
|
||
setTimeout(() => {
|
||
this.$team.reload();
|
||
}, 500);
|
||
|
||
this.$emit('disabled');
|
||
|
||
return '双因素认证已成功禁用';
|
||
},
|
||
error(err) {
|
||
if (err.messages) {
|
||
if (err.messages.includes('Invalid TOTP code')) {
|
||
return '无效的TOTP验证码,请重试';
|
||
} else {
|
||
return err.messages.join('.');
|
||
}
|
||
} else {
|
||
return '禁用双因素认证失败';
|
||
}
|
||
}
|
||
}
|
||
);
|
||
}
|
||
},
|
||
resources: {
|
||
qrUrl() {
|
||
return {
|
||
url: 'jcloud.api.account.get_2fa_qr_code_url',
|
||
auto: true,
|
||
onSuccess(qr_code_url) {
|
||
this.qrUrl = qr_code_url;
|
||
}
|
||
};
|
||
},
|
||
enable2FA() {
|
||
return {
|
||
url: 'jcloud.api.account.enable_2fa'
|
||
};
|
||
},
|
||
disable2FA() {
|
||
return {
|
||
url: 'jcloud.api.account.disable_2fa'
|
||
};
|
||
}
|
||
},
|
||
computed: {
|
||
setupKey() {
|
||
if (!this.qrUrl) return null;
|
||
return this.qrUrl.match(/secret=(.*?)&issuer/)[1];
|
||
},
|
||
is2FAEnabled() {
|
||
return this.$team.pg?.user_info?.is_2fa_enabled;
|
||
}
|
||
}
|
||
};
|
||
</script> |