用户密码支持自定义配置规则

This commit is contained in:
RuoYi
2026-04-17 13:11:38 +08:00
parent 3f4e93bd61
commit f89993e1af
5 changed files with 98 additions and 31 deletions
+2
View File
@@ -1,4 +1,5 @@
import router from '@/router' import router from '@/router'
import cache from '@/plugins/cache'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { login, logout, getInfo } from '@/api/login' import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from '@/utils/auth'
@@ -65,6 +66,7 @@ const useUserStore = defineStore(
this.name = user.userName || '' this.name = user.userName || ''
this.nickName = user.nickName || '' this.nickName = user.nickName || ''
this.avatar = avatar this.avatar = avatar
cache.session.set('pwrChrtype', res.pwdChrtype)
/* 初始密码提示 */ /* 初始密码提示 */
if(res.isDefaultModifyPwd) { if(res.isDefaultModifyPwd) {
ElMessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { ElMessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
+73
View File
@@ -0,0 +1,73 @@
/**
* 密码强度规则
* 根据参数 chrtype 动态生成校验规则
*
* chrtype 说明:
* 0 - 任意字符(默认)
* 1 - 纯数字(0-9
* 2 - 纯字母(a-z / A-Z
* 3 - 字母 + 数字(必须同时包含)
* 4 - 字母 + 数字 + 特殊字符(必须同时包含,特殊字符:~!@#$%^&*()-=_+
*/
import cache from '@/plugins/cache'
// 密码限制类型
const pwdChrType: Ref<string> = ref(cache.session.get('pwrChrtype') || '0')
// 各类型对应的正则、错误提示
const PWD_RULES: Record<string, { pattern: RegExp; message: string }> = {
'0': { pattern: /^[^<>"'|\\]+$/, message: '密码不能包含非法字符:< > " \' \\ |' },
'1': { pattern: /^[0-9]+$/, message: '密码只能为数字(0-9' },
'2': { pattern: /^[a-zA-Z]+$/, message: '密码只能为英文字母(a-z、A-Z' },
'3': { pattern: /^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$/, message: '密码必须同时包含字母和数字' },
'4': { pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[~!@#$%^&*()\-=_+])[A-Za-z\d~!@#$%^&*()\-=_+]+$/, message: '密码必须同时包含字母、数字和特殊字符(~!@#$%^&*()-=_+' }
}
export function usePasswordRule() {
// 默认密码校验
const pwdValidator = computed(() => {
const rule = PWD_RULES[pwdChrType.value] || PWD_RULES['0']
return [
{ required: true, message: '密码不能为空', trigger: 'blur' },
{ min: 6, max: 20, message: '密码长度必须介于 6 和 20 之间', trigger: 'blur' },
{ pattern: rule.pattern, message: rule.message, trigger: 'blur' }
]
})
// 校验prompt的inputValidator函数
const pwdPromptValidator = (value: string) => {
const rule = PWD_RULES['0']
if (!value || value.length < 6 || value.length > 20) {
return '密码长度必须介于 6 和 20 之间'
}
if (!rule.pattern.test(value)) {
return rule.message
}
}
// 个人中心密码校验
const infoPwdValidator = computed(() => {
const rule = PWD_RULES[pwdChrType.value] || PWD_RULES['0']
return [
{ required: true, message: '新密码不能为空', trigger: 'blur' },
{ min: 6, max: 20, message: '新密码长度必须介于 6 和 20 之间', trigger: 'blur' },
{ pattern: rule.pattern, message: rule.message, trigger: 'blur' }
]
})
// 注册页面密码校验
const registerPwdValidator = computed(() => {
const rule = PWD_RULES['0']
return [
{ required: true, message: '请输入您的密码', trigger: 'blur' },
{ min: 6, max: 20, message: '用户密码长度必须介于 6 和 20 之间', trigger: 'blur' },
{ pattern: rule.pattern, message: rule.message, trigger: 'blur' }
]
})
return {
pwdChrType,
pwdValidator,
infoPwdValidator,
pwdPromptValidator,
registerPwdValidator
}
}
+3 -6
View File
@@ -13,7 +13,7 @@
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password" :rules="registerPwdValidator">
<el-input <el-input
v-model="registerForm.password" v-model="registerForm.password"
type="password" type="password"
@@ -79,12 +79,14 @@
import { ElMessageBox } from "element-plus" import { ElMessageBox } from "element-plus"
import { getCodeImg, register } from "@/api/login" import { getCodeImg, register } from "@/api/login"
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import { usePasswordRule } from "@/utils/passwordRule"
import type { RegisterForm } from '@/types/api/login' import type { RegisterForm } from '@/types/api/login'
const title = import.meta.env.VITE_APP_TITLE const title = import.meta.env.VITE_APP_TITLE
const footerContent = defaultSettings.footerContent const footerContent = defaultSettings.footerContent
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { registerPwdValidator } = usePasswordRule()
const registerForm = ref<RegisterForm>({ const registerForm = ref<RegisterForm>({
username: "", username: "",
@@ -107,11 +109,6 @@ const registerRules = {
{ required: true, trigger: "blur", message: "请输入您的账号" }, { required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" } { min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
], ],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [ confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" }, { required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" } { required: true, validator: equalToPassword, trigger: "blur" }
+5 -11
View File
@@ -123,7 +123,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password"> <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" :rules="pwdValidator">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -187,6 +187,7 @@
import TreePanel from "@/components/TreePanel/index.vue" import TreePanel from "@/components/TreePanel/index.vue"
import ExcelImportDialog from "@/components/ExcelImportDialog/index.vue" import ExcelImportDialog from "@/components/ExcelImportDialog/index.vue"
import UserViewDrawer from "./view.vue" import UserViewDrawer from "./view.vue"
import { usePasswordRule } from "@/utils/passwordRule"
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user" import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
import type { SysUser, UserQueryParams, UserFormDataResult } from '@/types/api/system/user' import type { SysUser, UserQueryParams, UserFormDataResult } from '@/types/api/system/user'
import type { SysRole } from '@/types/api/system/role' import type { SysRole } from '@/types/api/system/role'
@@ -195,6 +196,7 @@ import type { TreeSelect, TableShowColumns, AjaxResult } from '@/types/api/commo
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { pwdValidator, pwdPromptValidator } = usePasswordRule()
const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex") const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex")
const userList = ref<SysUser[]>([]) const userList = ref<SysUser[]>([])
@@ -236,7 +238,6 @@ const data = reactive({
rules: { rules: {
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }], userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }], nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }], email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }] phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
} }
@@ -348,18 +349,11 @@ function handleAuthRole(row: SysUser) {
/** 重置密码按钮操作 */ /** 重置密码按钮操作 */
function handleResetPwd(row: SysUser) { function handleResetPwd(row: SysUser) {
proxy.$prompt('请输入"' + row.userName + '"的新密码', "提示", { proxy.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
closeOnClickModal: false, closeOnClickModal: false,
inputPattern: /^.{5,20}$/, inputValidator: pwdPromptValidator
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputValidator: (value: string) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
return true
},
}).then(({ value }: { value: string }) => { }).then(({ value }: { value: string }) => {
resetUserPwd(row.userId!, value).then(() => { resetUserPwd(row.userId!, value).then(() => {
proxy.$modal.msgSuccess("修改成功,新密码是:" + value) proxy.$modal.msgSuccess("修改成功,新密码是:" + value)
+15 -14
View File
@@ -1,25 +1,27 @@
<template> <template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px"> <el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword"> <el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password /> <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item> </el-form-item>
<el-form-item label="新密码" prop="newPassword"> <el-form-item label="新密码" prop="newPassword" :rules="infoPwdValidator">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password /> <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item> </el-form-item>
<el-form-item label="确认密码" prop="confirmPassword"> <el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/> <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="submit">保存</el-button> <el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button> <el-button type="danger" @click="close">关闭</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePasswordRule } from "@/utils/passwordRule"
import { updateUserPwd } from "@/api/system/user" import { updateUserPwd } from "@/api/system/user"
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { infoPwdValidator } = usePasswordRule()
interface UserProfilePwd { interface UserProfilePwd {
// 旧密码 // 旧密码
@@ -46,7 +48,6 @@ const equalToPassword = (rule: any, value: string, callback: (error?: Error) =>
const rules = { const rules = {
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }], oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }] confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
} }