diff --git a/package.json b/package.json index 6a6ad1d1..9ceb8432 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "postcss-purgecss": "^5.0.0", "prismjs": "^1.29.0", "pull-refresh-vue3": "^0.3.1", + "qrcode.vue": "^3.4.1", "roboto-fontface": "^0.10.0", "sass": "^1.59.3", "tailwindcss": "^3.3.2", @@ -109,4 +110,4 @@ "resolutions": { "postcss": "8" } -} \ No newline at end of file +} diff --git a/src/api/types.ts b/src/api/types.ts index d3deeeb3..d15921e2 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -850,6 +850,9 @@ export interface User { // 头像 avatar: string + + // 是否开启二次验证 + is_otp: boolean } // 存储空间 diff --git a/src/pages/login.vue b/src/pages/login.vue index 2a4498be..c36e79aa 100644 --- a/src/pages/login.vue +++ b/src/pages/login.vue @@ -13,6 +13,7 @@ const store = useStore() const form = ref({ username: '', password: '', + otp_password: '', remember: true, }) @@ -55,6 +56,7 @@ function login() { formData.append('username', form.value.username) formData.append('password', form.value.password) + formData.append('otp_password', form.value.otp_password) // 请求token api @@ -85,13 +87,13 @@ function login() { if (!error.response) errorMessage.value = '登录失败,请检查网络连接' else if (error.response.status === 401) - errorMessage.value = '登录失败,请检查用户名和密码是否正确' + errorMessage.value = '登录失败,请检查用户名、密码或二次验证是否正确' else if (error.response.status === 403) errorMessage.value = '登录失败,您没有权限访问' else if (error.response.status === 500) errorMessage.value = '登录失败,服务器错误' else - errorMessage.value = `登录失败 ${error.response.status},请检查用户名和密码是否正确` + errorMessage.value = `登录失败 ${error.response.status},请检查用户名、密码或二次验证是否正确` }) } @@ -174,7 +176,14 @@ onMounted(() => { > {{ errorMessage }} - + + +
() // 新增用户窗口 const addUserDialog = ref(false) +// 开启二次验证窗口 +const otpDialog = ref(false) + +// otp uri +const otpUri = ref('') + +// otp secret +const secret = ref('') + +// 确认二次验证密码 +const otpPassword = ref('') + // 新增用户表单 const userForm = reactive({ name: '', @@ -35,11 +48,15 @@ const accountInfo = ref({ is_active: false, is_superuser: false, avatar: '', + is_otp: false }) // 所有用户信息 const allUsers = ref([]) +// 二维码信息 +const qrCode = ref('') + // changeAvatar function function changeAvatar(file: Event) { const fileReader = new FileReader() @@ -65,7 +82,7 @@ function resetAvatar() { async function loadAccountInfo() { try { const user: User = await api.get('user/current') - + console.log(user) accountInfo.value = user if (!accountInfo.value.avatar) accountInfo.value.avatar = avatar1 @@ -167,6 +184,62 @@ async function addUser() { } } +// 为当前用户获取Otp Uri +async function getOtpUri() { + try { + const result: { [key: string]: any } = await api.post('user/otp/generate') + if (result.success) { + otpUri.value = result.data.uri + secret.value = result.data.secret + qrCode.value = result.data.uri + otpDialog.value = true + } else { + $toast.error(`获取otp uri失败:${result.message}!`) + } + } catch (error) { + console.log(error) + } +} + +// 关闭当前用户的二次验证 +async function disableOtp() { + try { + const result: { [key: string]: any } = await api.post('user/otp/disable') + if (result.success) { + accountInfo.value.is_otp = false; + $toast.success('关闭二次验证成功!') + } + else { + $toast.error(`关闭otp失败:${result.message}!`) + } + } catch (error) { + console.log(error) + } +} + +// 启用Otp +async function judgeOtpPassword() { + if (!otpPassword) { + $toast.error('请填写6位验证码') + return + } + try { + const result: { [key: string]: any } = await api.post('user/otp/judge', {'uri': otpUri.value, 'otpPassword': otpPassword.value}) + + if (result.success) { + $toast.success('开启二次验证成功!') + otpDialog.value = false + accountInfo.value.is_otp = true + } + else { + $toast.error(`开启otp失败:${result.message}!`) + } + } + catch (error) { + console.log(error) + } +} + // 加载当前用户数据 onMounted(() => { loadAccountInfo() @@ -222,6 +295,16 @@ onMounted(() => { class="d-sm-none" /> + + + + {{accountInfo.is_otp? "关闭验证": "二次验证"}} +

@@ -470,4 +553,50 @@ onMounted(() => { + + + + + + + + + + + + + 1、你可以使用 Microsoft Authenticator (谷歌或其他支持软件如Keeper等) 软件扫描左侧二维码 + 或者在 APP 中手动输入以下 Key +

{{secret}}

+ + + 2、在 APP 中获取6位验证码并输入 + + + + +
+ + + + + 取消 + + + + 确定 + + + + diff --git a/src/views/setting/AccountSettingSystem.vue b/src/views/setting/AccountSettingSystem.vue index c819fca6..b518d89f 100644 --- a/src/views/setting/AccountSettingSystem.vue +++ b/src/views/setting/AccountSettingSystem.vue @@ -184,7 +184,7 @@ async function saveMediaSetting() { } // 调用API查询下载器设置 -async function loadDownladerSetting() { +async function loadDownloaderSetting() { try { const result1: { [key: string]: any } = await api.get('system/setting/DOWNLOADER') if (result1.success) @@ -330,7 +330,7 @@ async function reloadModule() { // 加载数据 onMounted(() => { - loadDownladerSetting() + loadDownloaderSetting() loadMediaServerSetting() loadMediaSettings() }) diff --git a/yarn.lock b/yarn.lock index 75d7a5e7..b66e10d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6461,6 +6461,11 @@ purgecss@^5.0.0: postcss "^8.4.4" postcss-selector-parser "^6.0.7" +qrcode.vue@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/qrcode.vue/-/qrcode.vue-3.4.1.tgz#dd8141da9c4ea07ee56b111cd13eadf123af822a" + integrity sha512-wq/zHsifH4FJ1GXQi8/wNxD1KfQkckIpjK1KPTc/qwYU5/Bkd4me0w4xZSg6EXk6xLBkVDE0zxVagewv5EMAVA== + qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"