This commit is contained in:
zss
2024-03-28 16:35:20 +08:00
parent eee0c0c878
commit 34b418af96
6 changed files with 154 additions and 7 deletions

View File

@@ -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"
}
}
}

View File

@@ -850,6 +850,9 @@ export interface User {
// 头像
avatar: string
// 是否开启二次验证
is_otp: boolean
}
// 存储空间

View File

@@ -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 }}
</div>
</VCol>
<VCol cols="12">
<VTextField
hint="非必传,如开启二次验证需填写"
v-model="form.otp_password"
label="二次验证"
type="input"
/>
<!-- remember me checkbox -->
<div class="d-flex align-center justify-space-between flex-wrap mt-1 mb-4">
<VCheckbox

View File

@@ -4,6 +4,7 @@ import { requiredValidator } from '@/@validators'
import api from '@/api'
import type { User } from '@/api/types'
import avatar1 from '@images/avatars/avatar-1.png'
import QrcodeVue from 'qrcode.vue'
const isNewPasswordVisible = ref(false)
const isConfirmPasswordVisible = ref(false)
@@ -19,6 +20,18 @@ const refInputEl = ref<HTMLElement>()
// 新增用户窗口
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<User>({
is_active: false,
is_superuser: false,
avatar: '',
is_otp: false
})
// 所有用户信息
const allUsers = ref<User[]>([])
// 二维码信息
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"
/>
</VBtn>
<VBtn
:color="accountInfo.is_otp? 'error': 'info'"
@click.stop="accountInfo.is_otp? disableOtp(): getOtpUri()"
>
<VIcon
icon="mdi-account-key"
/>
<span class="d-none d-sm-block">{{accountInfo.is_otp? "关闭验证": "二次验证"}}</span>
</VBtn>
</div>
<p class="text-body-1 mb-0">
@@ -470,4 +553,50 @@ onMounted(() => {
</VCardActions>
</VCard>
</VDialog>
<!-- 二次验证弹窗 -->
<VDialog
v-model="otpDialog"
max-width="40rem"
persistent
z-index="1010"
>
<!-- 开启二次验证弹窗内容 -->
<VCard title="二次验证">
<VCardText>
<VRow>
<VCol>
<QrcodeVue :value="qrCode" :size="200" max-width="25rem"/>
</VCol>
<VCol>
<VRow>
1你可以使用 Microsoft Authenticator (谷歌或其他支持软件如Keeper等) 软件扫描左侧二维码
或者在 APP 中手动输入以下 Key
<h1>{{secret}}</h1>
</VRow>
<VRow>
2 APP 中获取6位验证码并输入
</VRow>
<VRow>
<VTextField
v-model="otpPassword"
type="text"
label="输入验证码以确认开启双重验证"
autocomplete="otpPassword"
/>
</VRow>
</VCol>
</VRow>
</VCardText>
<VCardActions>
<VBtn @click="otpDialog = false">
取消
</VBtn>
<VSpacer />
<VBtn @click="judgeOtpPassword">
确定
</VBtn>
</VCardActions>
</VCard>
</VDialog>
</template>

View File

@@ -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()
})

View File

@@ -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"