加固后台管理安全
This commit is contained in:
@@ -27,17 +27,24 @@ import {
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElSubMenu } from 'element-plus'
|
||||
import type { Component } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { logoutAdmin, updateSupportStatus } from '@/features/admin'
|
||||
import { changeAdminPassword, logoutAdmin, updateSupportStatus } from '@/features/admin'
|
||||
import { useAdminSessionStore } from '@/stores/adminSession'
|
||||
import { readError } from '@/shared/utils/error'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const adminSession = useAdminSessionStore()
|
||||
const isCollapsed = ref(false)
|
||||
const updatingStatus = ref(false)
|
||||
const passwordSubmitting = ref(false)
|
||||
const passwordForm = reactive({
|
||||
old_password: '',
|
||||
new_password: '',
|
||||
confirm_password: '',
|
||||
})
|
||||
|
||||
interface NavItem {
|
||||
label: string
|
||||
@@ -231,6 +238,39 @@ async function handleLogout() {
|
||||
ElMessage.success('已退出后台')
|
||||
await router.push('/admin/login')
|
||||
}
|
||||
|
||||
function passwordStrongEnough(value: string) {
|
||||
return value.length >= 8 && /[A-Za-z]/.test(value) && /\d/.test(value)
|
||||
}
|
||||
|
||||
async function handleForcedPasswordChange() {
|
||||
if (!passwordForm.old_password || !passwordForm.new_password) {
|
||||
ElMessage.error('请输入原密码和新密码')
|
||||
return
|
||||
}
|
||||
if (!passwordStrongEnough(passwordForm.new_password)) {
|
||||
ElMessage.error('新密码至少 8 位且需包含字母和数字')
|
||||
return
|
||||
}
|
||||
if (passwordForm.new_password !== passwordForm.confirm_password) {
|
||||
ElMessage.error('两次输入的新密码不一致')
|
||||
return
|
||||
}
|
||||
passwordSubmitting.value = true
|
||||
try {
|
||||
await changeAdminPassword({
|
||||
old_password: passwordForm.old_password,
|
||||
new_password: passwordForm.new_password,
|
||||
})
|
||||
ElMessage.success('密码已修改,请重新登录')
|
||||
adminSession.logout()
|
||||
await router.replace('/admin/login')
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, '密码修改失败'))
|
||||
} finally {
|
||||
passwordSubmitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -332,6 +372,51 @@ async function handleLogout() {
|
||||
<slot />
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<el-dialog
|
||||
:model-value="adminSession.passwordMustChange"
|
||||
title="修改初始密码"
|
||||
width="420px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
class="force-password-dialog"
|
||||
>
|
||||
<el-form class="force-password-form" label-position="top" @submit.prevent>
|
||||
<el-form-item label="原密码">
|
||||
<el-input
|
||||
v-model="passwordForm.old_password"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码">
|
||||
<el-input
|
||||
v-model="passwordForm.new_password"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认新密码">
|
||||
<el-input
|
||||
v-model="passwordForm.confirm_password"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
@keyup.enter="handleForcedPasswordChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button :disabled="passwordSubmitting" @click="handleLogout">退出登录</el-button>
|
||||
<el-button type="primary" :loading="passwordSubmitting" @click="handleForcedPasswordChange">
|
||||
确认修改
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -572,4 +657,13 @@ async function handleLogout() {
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
:global(.force-password-dialog) {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.force-password-form {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user