feat: 更新应用标题和描述,调整谷歌验证和登录流程以支持二步验证

This commit is contained in:
2026-01-20 07:09:11 +07:00
parent 220b14be30
commit 322530e45f
6 changed files with 99 additions and 37 deletions

View File

@@ -1,8 +1,9 @@
import { computed, reactive, ref } from 'vue';
import { computed, h, reactive, ref } from 'vue';
import { useRoute } from 'vue-router';
import { defineStore } from 'pinia';
import { NInputOtp } from 'naive-ui';
import { useLoading } from '@sa/hooks';
import { fetchLogin } from '@/service/api';
import { authClient, fetchLogin, safeClient } from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
@@ -102,24 +103,40 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const res = await fetchLogin(userName, password);
if (!res.error) {
const pass = await loginByToken(res.data);
if ('twoFactorRedirect' in res.data && res.data.twoFactorRedirect) {
const topt = ref('');
window.$dialog?.create({
title: '谷歌验证',
content: () =>
h(NInputOtp, {
style: { margin: '30px 0' },
size: 'large',
allowInput: value => !value || /^\d+$/.test(value),
onUpdateValue: value => {
topt.value = value.join('');
}
}),
positiveText: '下一步',
negativeText: '取消',
onPositiveClick: async () => {
if (!topt.value) {
window.$message?.error('请输入密码');
} else {
const { data } = await safeClient(
authClient.twoFactor.verifyTotp({
code: topt.value, // required
trustDevice: false // 管理员登录不建议信任设备,以提高安全性
})
);
if (pass) {
// Check if the tab needs to be cleared
const isClear = checkTabClear();
let needRedirect = redirect;
if (isClear) {
// If the tab needs to be cleared,it means we don't need to redirect.
needRedirect = false;
}
await redirectFromLogin(needRedirect);
window.$notification?.success({
title: $t('page.login.common.loginSuccess'),
content: $t('page.login.common.welcomeBack', { userName: userInfo.name }),
duration: 4500
if (data.value) {
saveLogin(data.value, redirect);
}
}
}
});
} else {
saveLogin(res.data, redirect);
}
} else {
resetStore();
@@ -128,6 +145,28 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
endLoading();
}
async function saveLogin(data: Api.Auth.LoginToken, redirect = true) {
const pass = await loginByToken(data);
if (pass) {
// Check if the tab needs to be cleared
const isClear = checkTabClear();
let needRedirect = redirect;
if (isClear) {
// If the tab needs to be cleared,it means we don't need to redirect.
needRedirect = false;
}
await redirectFromLogin(needRedirect);
window.$notification?.success({
title: $t('page.login.common.loginSuccess'),
content: $t('page.login.common.welcomeBack', { userName: userInfo.name }),
duration: 4500
});
}
}
async function loginByToken(data: Api.Auth.LoginToken) {
// 1. stored in the localStorage, the later requests need it in headers
localStg.set('token', data.token);