RuoYi
2026-04-17 397971378357db417763bd388c25cdeeaed5d33c
用户密码支持自定义配置规则
1 files added
1 files renamed
5 files modified
178 ■■■■ changed files
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java 7 ●●●●● patch | view | raw | blame | history
ruoyi-ui/src/store/modules/user.js 2 ●●●●● patch | view | raw | blame | history
ruoyi-ui/src/utils/passwordRule.js 71 ●●●●● patch | view | raw | blame | history
ruoyi-ui/src/views/register.vue 41 ●●●● patch | view | raw | blame | history
ruoyi-ui/src/views/system/user/index.vue 19 ●●●● patch | view | raw | blame | history
ruoyi-ui/src/views/system/user/profile/resetPwd.vue 37 ●●●● patch | view | raw | blame | history
sql/ry_20260417.sql 1 ●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
@@ -189,11 +189,18 @@
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("pwdChrtype", getSysAccountChrtype());
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }
    // 获取用户密码自定义配置规则
    public String getSysAccountChrtype()
    {
        return Convert.toStr(configService.selectConfigByKey("sys.account.chrtype"), "0");
    }
    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
ruoyi-ui/src/store/modules/user.js
@@ -1,5 +1,6 @@
import store from '@/store'
import router from '@/router'
import cache from '@/plugins/cache'
import { MessageBox, } from 'element-ui'
import { login, logout, getInfo, refreshToken } from '@/api/login'
import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth'
@@ -82,6 +83,7 @@
          commit('SET_NAME', user.userName)
          commit('SET_NICK_NAME', user.nickName)
          commit('SET_AVATAR', avatar)
          cache.session.set('pwrChrtype', res.pwdChrtype)
          /* 初始密码提示 */
          if(res.isDefaultModifyPwd) {
            MessageBox.confirm('您的密码还是初始密码,请修改密码!',  '安全提示', {  confirmButtonText: '确定',  cancelButtonText: '取消',  type: 'warning' }).then(() => {
ruoyi-ui/src/utils/passwordRule.js
New file
@@ -0,0 +1,71 @@
/**
 * 密码强度规则
 * 根据参数 chrtype 动态生成校验规则
 *
 * chrtype 说明:
 *   0 - 任意字符(默认)
 *   1 - 纯数字(0-9)
 *   2 - 纯字母(a-z / A-Z)
 *   3 - 字母 + 数字(必须同时包含)
 *   4 - 字母 + 数字 + 特殊字符(必须同时包含,特殊字符:~!@#$%^&*()-=_+)
 */
import cache from '@/plugins/cache'
// 各类型对应的正则、错误提示
const PWD_RULES = {
  '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 default {
  data() {
    return {
      // 密码限制类型
      pwdChrType: cache.session.get('pwrChrtype') || '0'
    }
  },
  computed: {
    // 默认密码校验
    pwdValidator() {
      const rule = PWD_RULES[this.pwdChrType] || 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函数
    pwdPromptValidator() {
      const rule = PWD_RULES['0']
      return (value) => {
        if (!value || value.length < 6 || value.length > 20) {
          return '密码长度必须介于 6 和 20 之间'
        }
        if (!rule.pattern.test(value)) {
          return rule.message
        }
      }
    },
    // 个人中心密码校验
    infoPwdValidator() {
      const rule = PWD_RULES[this.pwdChrType] || 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' }
      ]
    },
    // 注册页面密码校验
    registerPwdValidator() {
      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' }
      ]
    }
  }
}
ruoyi-ui/src/views/register.vue
@@ -7,7 +7,7 @@
          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
      <el-form-item prop="password" :rules="registerPwdValidator">
        <el-input
          v-model="registerForm.password"
          type="password"
@@ -68,18 +68,12 @@
<script>
import { getCodeImg, register } from "@/api/login"
import passwordRule from "@/utils/passwordRule"
import defaultSettings from '@/settings'
export default {
  name: "Register",
  mixins: [passwordRule],
  data() {
    const equalToPassword = (rule, value, callback) => {
      if (this.registerForm.password !== value) {
        callback(new Error("两次输入的密码不一致"))
      } else {
        callback()
      }
    }
    return {
      title: process.env.VUE_APP_TITLE,
      footerContent: defaultSettings.footerContent,
@@ -91,24 +85,31 @@
        code: "",
        uuid: ""
      },
      registerRules: {
      loading: false,
      captchaEnabled: true
    }
  },
  computed: {
    registerRules() {
      return {
        username: [
          { required: true, trigger: "blur", message: "请输入您的账号" },
          { 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: [
          { required: true, trigger: "blur", message: "请再次输入您的密码" },
          { required: true, validator: equalToPassword, trigger: "blur" }
          { required: true, message: "请再次输入您的密码", trigger: "blur" },
          {
            validator: (rule, value, callback) => {
              if (this.registerForm.password !== value) {
                callback(new Error("两次输入的密码不一致"))
              } else {
                callback()
              }
            }, trigger: "blur"
          }
        ],
        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
      },
      loading: false,
      captchaEnabled: true
      }
    }
  },
  created() {
ruoyi-ui/src/views/system/user/index.vue
@@ -116,7 +116,7 @@
            </el-form-item>
          </el-col>
          <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-form-item>
          </el-col>
@@ -181,9 +181,11 @@
import TreePanel from "@/components/TreePanel"
import ExcelImportDialog from "@/components/ExcelImportDialog"
import UserViewDrawer from "./view"
import passwordRule from "@/utils/passwordRule"
export default {
  name: "User",
  mixins: [passwordRule],
  dicts: ['sys_normal_disable', 'sys_user_sex'],
  components: { Treeselect, TreePanel, ExcelImportDialog, UserViewDrawer },
  data() {
@@ -247,11 +249,6 @@
        ],
        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: [
          {
@@ -405,17 +402,11 @@
    },
    /** 重置密码按钮操作 */
    handleResetPwd(row) {
      this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
      this.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        closeOnClickModal: false,
        inputPattern: /^.{5,20}$/,
        inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
        inputValidator: (value) => {
          if (/<|>|"|'|\||\\/.test(value)) {
            return "不能包含非法字符:< > \" ' \\\ |"
          }
        },
        inputValidator: this.pwdPromptValidator
      }).then(({ value }) => {
        resetUserPwd(row.userId, value).then(() => {
          this.$modal.msgSuccess("修改成功,新密码是:" + value)
ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -1,9 +1,9 @@
<template>
  <el-form ref="form" :model="user" :rules="rules" label-width="80px">
  <el-form ref="form" :model="user" :rules="formRules" label-width="80px">
    <el-form-item label="旧密码" prop="oldPassword">
      <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
    </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-form-item>
    <el-form-item label="确认密码" prop="confirmPassword">
@@ -18,35 +18,36 @@
<script>
import { updateUserPwd } from "@/api/system/user"
import passwordRule from "@/utils/passwordRule"
export default {
  mixins: [passwordRule],
  data() {
    const equalToPassword = (rule, value, callback) => {
      if (this.user.newPassword !== value) {
        callback(new Error("两次输入的密码不一致"))
      } else {
        callback()
      }
    }
    return {
      user: {
        oldPassword: undefined,
        newPassword: undefined,
        confirmPassword: undefined
      },
      // 表单校验
      rules: {
      }
    }
  },
  computed: {
    formRules() {
      return {
        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" }
          {
            validator: (rule, value, callback) => {
              if (this.user.newPassword !== value) {
                callback(new Error("两次输入的密码不一致"))
              } else {
                callback()
              }
            }, trigger: "blur"
          }
        ]
      }
    }
sql/ry_20260417.sql
File was renamed from sql/ry_20260402.sql
@@ -552,6 +552,7 @@
insert into sys_config values(5, '用户登录-黑名单列表',           'sys.login.blackIPList',            '',              'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
insert into sys_config values(6, '用户管理-初始密码修改策略',     'sys.account.initPasswordModify',   '1',             'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
insert into sys_config values(7, '用户管理-账号密码更新周期',     'sys.account.passwordValidateDays', '0',             'Y', 'admin', sysdate(), '', null, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框');
insert into sys_config values(8, '用户管理-密码字符范围',         'sys.account.chrtype',              '0',             'Y', 'admin', sysdate(), '', null, '默认任意字符范围,0任意(密码可以输入任意字符),1数字(密码只能为0-9数字),2英文字母(密码只能为a-z和A-Z字母),3字母和数字(密码必须包含字母,数字),4字母数字和特殊字符(目前支持的特殊字符包括:~!@#$%^&*()-=_+)');
-- ----------------------------