Bläddra i källkod

增加密码规则

xusl 2 år sedan
förälder
incheckning
752b25e9a9

+ 43 - 0
backend/src/main/java/com/jiayue/ssi/backenum/PasswordRuleEnum.java

@@ -0,0 +1,43 @@
+package com.jiayue.ssi.backenum;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+* 密码规则枚举
+*
+* @author xsl
+* @since 2023/06/06
+*/
+@Getter
+@AllArgsConstructor
+public enum PasswordRuleEnum {
+    /**
+     * 大写字母
+     */
+    A("大写字母", ".*[A-Z]+.*"),
+    /**
+     * 小写字母
+     */
+    B("小写字母", ".*[a-z]+.*"),
+    /**
+     * 数字
+     */
+    C("数字", ".*\\d+.*"),
+    /**
+     * 特殊字符
+     */
+    D("特殊字符", ".*[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+.*");
+
+    private String code;
+    private String message;
+
+    public static PasswordRuleEnum getByName(String name) {
+        for (PasswordRuleEnum type : values()) {
+            if (type.name().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}

+ 5 - 0
backend/src/main/java/com/jiayue/ssi/constant/CacheConstants.java

@@ -62,4 +62,9 @@ public class CacheConstants {
      * ip黑名单缓存
      */
     public static ConcurrentMap<String, Long> blacklistMap = new ConcurrentHashMap<>();
+
+    /**
+     * 用户名对应明文密码缓存
+     */
+    public static ConcurrentMap<String, String> usernamePasswordMap = new ConcurrentHashMap<>();
 }

+ 39 - 21
backend/src/main/java/com/jiayue/ssi/controller/SysUserController.java

@@ -3,28 +3,19 @@ package com.jiayue.ssi.controller;
 import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.crypto.SmUtil;
-import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.jiayue.ssi.annotation.AgainVerify;
-import com.jiayue.ssi.annotation.InterfaceLimit;
 import com.jiayue.ssi.annotation.OperateLog;
 import com.jiayue.ssi.annotation.PreventReplay;
-import com.jiayue.ssi.backenum.ApproveOperaterEnum;
 import com.jiayue.ssi.backenum.ApproveStatusEnum;
 import com.jiayue.ssi.backenum.AuditType;
 import com.jiayue.ssi.backenum.BusinessType;
 import com.jiayue.ssi.config.SendMailUtil;
+import com.jiayue.ssi.constant.CacheConstants;
 import com.jiayue.ssi.constant.CustomException;
-import com.jiayue.ssi.constant.SecretKeyConstants;
-import com.jiayue.ssi.entity.SysApprove;
-import com.jiayue.ssi.entity.SysRole;
-import com.jiayue.ssi.entity.SysUser;
-import com.jiayue.ssi.entity.SysUserRole;
-import com.jiayue.ssi.service.SysApproveService;
-import com.jiayue.ssi.service.SysRoleService;
-import com.jiayue.ssi.service.SysUserRoleService;
-import com.jiayue.ssi.service.SysUserService;
+import com.jiayue.ssi.entity.*;
+import com.jiayue.ssi.service.*;
 import com.jiayue.ssi.service.impl.SysPermissionService;
 import com.jiayue.ssi.util.*;
 import lombok.extern.slf4j.Slf4j;
@@ -57,6 +48,8 @@ public class SysUserController {
     SysApproveService sysApproveService;
     @Autowired
     SysRoleService sysRoleService;
+    @Autowired
+    SysPolicyService sysPolicyService;
 
     /**
      * 获取用户分页信息
@@ -411,6 +404,10 @@ public class SysUserController {
     @PreventReplay
     public ResponseVO updatePassword(String id, String oldPassword, String newPassword, String confirmPassword) throws CustomException {
         try {
+            oldPassword = oldPassword.trim();
+            newPassword = newPassword.trim();
+            confirmPassword = confirmPassword.trim();
+
             if (StringUtils.isEmpty(id)) {
                 return ResponseVO.fail("修改密码缺失id!");
             }
@@ -429,7 +426,12 @@ public class SysUserController {
             // id获取用户
             SysUser sysUser = sysUserService.getById(id);
             if (sysUser == null) {
-                return ResponseVO.fail("修改密码失败!");
+                return ResponseVO.fail("找不到用户,修改密码失败!");
+            }
+
+            if (newPassword == null || newPassword.length() < 8 || newPassword.length() > 20) {
+                // 返回密码长度问题
+                return ResponseVO.fail("密码长度需要8~20位之间!");
             }
 
             if (StringUtils.isEmpty(oldPassword)) {
@@ -452,14 +454,11 @@ public class SysUserController {
             if (SmUtil.sm3(newPassword).toUpperCase().equals(sysUser.getPassword())) {
                 return ResponseVO.fail("新密码不能与上次密码相同!");
             }
-            if (RegexUtil.sameReg(newPassword)) {
-                return ResponseVO.fail("新密码不能含有连续4位相同的数字或字母!");
-            } else if (RegexUtil.keyboardSlopeArr(newPassword)) {
-                return ResponseVO.fail("新密码不能含有4位斜方向连续的字符!");
-            } else if (RegexUtil.keyboardHorizontalReg(newPassword)) {
-                return ResponseVO.fail("新密码不能含有4位连续的字符!");
-            } else if (!RegexUtil.checkPwd(newPassword)) {
-                return ResponseVO.fail("新密码不满足8~20位大写字母、小写字母、数字、特殊字符三种以上的组合!");
+
+            SysPolicy sysPolicy = sysPolicyService.getOne(new QueryWrapper<>());
+            String ruleInfo = PasswordRuleUtil.ruleRegx(sysPolicy.getPasswordRule(),newPassword);
+            if (!"true".equals(ruleInfo)){
+                return ResponseVO.fail(ruleInfo);
             }
 
             sysUser.setPassword(SmUtil.sm3(newPassword).toUpperCase());
@@ -595,4 +594,23 @@ public class SysUserController {
             throw new CustomException("获取用户角色异常", e);
         }
     }
+
+    /**
+     * 检测用户密码是否符合规则
+     *
+     * @return 用户信息
+     */
+    @GetMapping(value = "/validatePasswordRule")
+    public ResponseVO validatePasswordRule() throws CustomException {
+        try {
+            SysUser sysUser = SecurityContextUtil.getSysUser();
+            String upwd = CacheConstants.usernamePasswordMap.get(sysUser.getUsername());
+            SysPolicy sysPolicy = sysPolicyService.getOne(new QueryWrapper<>());
+            String ruleInfo = PasswordRuleUtil.ruleRegx(sysPolicy.getPasswordRule(),upwd);
+            return ResponseVO.success(ruleInfo);
+        } catch (Exception e) {
+            throw new CustomException("检测用户密码是否符合规则异常", e);
+        }
+    }
+
 }

+ 0 - 9
backend/src/main/java/com/jiayue/ssi/controller/UserLoginController.java

@@ -48,15 +48,6 @@ public class UserLoginController {
      */
     @GetMapping("/getVerifyCode")
     public ResponseVO getVerifyCode(String murmur,HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws CustomException {
-        // gif类型
-        // GifCaptcha captcha = new GifCaptcha(130, 48);
-        // 中文类型
-        // ChineseCaptcha captcha = new ChineseCaptcha(130, 48);
-        // 中文gif类型
-        // ChineseGifCaptcha captcha = new ChineseGifCaptcha(130, 48);
-        // 算术类型
-        // ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48);
-        // png类型
         // 三个参数分别为宽、高、位数
         try {
             if (murmur.length()!=32){

+ 4 - 0
backend/src/main/java/com/jiayue/ssi/entity/SysPolicy.java

@@ -48,6 +48,10 @@ public class SysPolicy extends BaseEntity{
      */
     private Integer memoryWarn;
     /**
+     * 密码规则,多个规则用逗号分隔
+     */
+    private String passwordRule;
+    /**
      * 连续登录失败异常级别设置(0:A 1:B两个级别)
      */
     private String excLevelLogin;

+ 2 - 2
backend/src/main/java/com/jiayue/ssi/filter/InterfaceLimitFilter.java

@@ -47,7 +47,7 @@ public class InterfaceLimitFilter extends OncePerRequestFilter {
             response.setHeader("Access-Control-Allow-Origin", "*");
             response.setStatus(410);
             response.setContentType("text/html;charset=utf-8");
-            response.getWriter().write("IP已进黑名单,请联系管理员!");
+            response.getWriter().write("访问频率过快,IP已进黑名单,请联系管理员!");
             return;
         }
         if (!InterfaceLimitUtil.checkInterface(request, 1000, 10)) {
@@ -64,7 +64,7 @@ public class InterfaceLimitFilter extends OncePerRequestFilter {
             response.setHeader("Access-Control-Allow-Origin", "*");
             response.setStatus(410);
             response.setContentType("text/html;charset=utf-8");
-            response.getWriter().write("IP已进黑名单,请联系管理员!");
+            response.getWriter().write("访问频率过快,IP已进黑名单,请联系管理员!");
             return;
         }
         filterChain.doFilter(request, response);

+ 1 - 1
backend/src/main/java/com/jiayue/ssi/handler/CustomAuthenticationSuccessHandler.java

@@ -64,8 +64,8 @@ public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthent
         sysUser.setLoginIp(IPUtils.getIpAddr(request));
         sysUser.setLoginDate(new Date());
         sysUserService.updateUser(sysUser);
-
         SecurityContextHolder.getContext().setAuthentication(authentication);
+        CacheConstants.usernamePasswordMap.put(username,request.getParameter("password"));
 
         // 记录用户退出日志
         LoginFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");

+ 47 - 0
backend/src/main/java/com/jiayue/ssi/util/PasswordRuleUtil.java

@@ -0,0 +1,47 @@
+package com.jiayue.ssi.util;
+
+import com.jiayue.ssi.backenum.PasswordRuleEnum;
+
+/**
+ * 密码规则验证工具
+ *
+ * @author xsl
+ * @since 2023/06/06
+ */
+public class PasswordRuleUtil {
+    /**
+     * 根据规则验证密码
+     *
+     * @param pwdRule 密码规则,多个规则用逗号分隔
+     * @param pwd     密码
+     * @return
+     */
+    public static String ruleRegx(String pwdRule, String pwd) {
+        String[] rules = pwdRule.split(",");
+        if (rules.length<3){
+            return "密码规则至少3种以上组合!";
+        }
+        String retName = "";
+        for (int i = 0; i < rules.length; i++) {
+            // 获取正则
+            String regx = PasswordRuleEnum.valueOf(rules[i]).getMessage();
+            if (regx == null) {
+                // 正则不存在,传入的校验规则有问题
+                return "密码规则配置有问题,不能校验!";
+            } else {
+                retName = retName + PasswordRuleEnum.valueOf(rules[i]).getCode() + "、";
+            }
+        }
+
+        for (int i = 0; i < rules.length; i++) {
+            if (!pwd.matches(PasswordRuleEnum.valueOf(rules[i]).getMessage())){
+                return "密码不满足"+retName.substring(0,retName.length()-1)+"组合";
+            }
+        }
+        return "true";
+    }
+
+    public static void main(String[] args) {
+        System.out.println(ruleRegx("A,B,C", "abcde111W"));
+    }
+}

+ 1 - 1
backend/src/test/java/com/jiayue/ssi/service/Test.java

@@ -66,6 +66,6 @@ public class Test {
 //        System.out.println(map.get("username"));
 //        System.out.println(map.get("password"));
 
-        System.out.println(SmUtil.sm3("admin").toUpperCase());
+        System.out.println(SmUtil.sm3("Xsl@258369").toUpperCase());
     }
 }

+ 28 - 1
ui/src/App.vue

@@ -23,6 +23,33 @@ export default {
     //   }
     //
     // })
-  }
+
+    // window.addEventListener('beforeunload', e => this.beforeunloadHandler(e));
+  },
+  // destroyed() {
+  //   // 关闭浏览器执行退出接口
+  //   window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))
+  // },
+  // methods: {
+  //   // 关闭窗口之前执行
+  //   async beforeunloadHandler(e) {
+  //     await this.clearLogin() // 退出登录接口
+  //     // this._beforeUnload_time = new Date().getTime()
+  //     // console.log('this._beforeUnload_time:', this._beforeUnload_time)
+  //     window.close()
+  //   },
+  //   // 退出登录接口
+  //   clearLogin() {
+  //     alert('等处。。。。')
+  //     this.$axios.post(
+  //       '/logout', {}
+  //     ).then((res) => {
+  //       this.$message.success(res.data)
+  //       removeToken()
+  //       //注销返回自己的登录页
+  //       this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+  //     })
+  //   }
+  // }
 }
 </script>

+ 97 - 61
ui/src/layout/components/Navbar.vue

@@ -1,27 +1,28 @@
 <template>
   <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container"
+               @toggleClick="toggleSideBar"/>
 
     <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
     <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/>
 
     <div class="right-menu">
-<!--      <template v-if="device!=='mobile'">-->
-<!--        <search id="header-search" class="right-menu-item" />-->
+      <!--      <template v-if="device!=='mobile'">-->
+      <!--        <search id="header-search" class="right-menu-item" />-->
 
-<!--        <el-tooltip content="源码地址" effect="dark" placement="bottom">-->
-<!--          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
-<!--        </el-tooltip>-->
+      <!--        <el-tooltip content="源码地址" effect="dark" placement="bottom">-->
+      <!--          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
+      <!--        </el-tooltip>-->
 
-<!--        <el-tooltip content="文档地址" effect="dark" placement="bottom">-->
-<!--          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
-<!--        </el-tooltip>-->
+      <!--        <el-tooltip content="文档地址" effect="dark" placement="bottom">-->
+      <!--          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
+      <!--        </el-tooltip>-->
 
       <!-- 消息中心 -->
       <span v-show="alarmIconShow">
         <span v-if="isMessage" key="1">
           <el-tooltip content="告警消息" placement="bottom">
-            <a href='javascript:;' @click="showAlarm" >
+            <a href='javascript:;' @click="showAlarm">
               <svg-icon icon-class="notice" class="right-menu-item1 hover-effect1"/>
             </a>
           </el-tooltip>
@@ -35,18 +36,18 @@
 
 
       <el-tooltip content="全屏" placement="bottom">
-      <screenfull id="screenfull" class="right-menu-item hover-effect" />
+        <screenfull id="screenfull" class="right-menu-item hover-effect"/>
       </el-tooltip>
-<!--        <el-tooltip content="布局大小" effect="dark" placement="bottom">-->
-<!--          <size-select id="size-select" class="right-menu-item hover-effect" />-->
-<!--        </el-tooltip>-->
+      <!--        <el-tooltip content="布局大小" effect="dark" placement="bottom">-->
+      <!--          <size-select id="size-select" class="right-menu-item hover-effect" />-->
+      <!--        </el-tooltip>-->
 
-<!--      </template>-->
+      <!--      </template>-->
 
       <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
         <div class="avatar-wrapper">
           <img src="@/assets/img1.jpg" class="user-avatar">
-          <i class="el-icon-caret-bottom" />
+          <i class="el-icon-caret-bottom"/>
         </div>
         <el-dropdown-menu slot="dropdown">
           <router-link to="/user/profile">
@@ -74,17 +75,17 @@
           max-height="700"
           :data="alarmList"
         >
-          <vxe-table-column field="alarmContent" title="告警内容" />
+          <vxe-table-column field="alarmContent" title="告警内容"/>
           <vxe-table-column field="createTime" title="时间" width="200px"/>
           <vxe-table-column title="操作" width="100px">
             <template slot-scope="scope">
-            <el-button
-              size="mini"
-              type="text"
-              icon="el-icon-reading"
-              @click="readDone(scope.row)"
-            >查收
-            </el-button>
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-reading"
+                @click="readDone(scope.row)"
+              >查收
+              </el-button>
             </template>
           </vxe-table-column>
         </vxe-table>
@@ -97,7 +98,7 @@
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
+import {mapGetters} from 'vuex'
 import Breadcrumb from '@/components/Breadcrumb'
 import TopNav from '@/components/TopNav'
 import Hamburger from '@/components/Hamburger'
@@ -116,11 +117,11 @@ export default {
   data() {
     return {
       interval: null,
-      isMessage:false,
-      alarmIconShow:false,
-      title:'告警消息',
-      loading:false,
-      alarmList:null,
+      isMessage: false,
+      alarmIconShow: false,
+      title: '告警消息',
+      loading: false,
+      alarmList: null,
       // 是否显示弹出层
       open: false,
       message: 2
@@ -168,26 +169,36 @@ export default {
     }
   },
   methods: {
-    async getCurrentUser(){
+    async getCurrentUser() {
       var user;
-       await this.$axios.get('/sysUserController/getCurrentUser').then((res) => {
-         user = res.data.sysUser
+      let sysTime1
+      let lk1
+      await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
+        sysTime1 = res.data.sysTime
+        lk1 = res.data.lk
+      }).catch((error) => {
+      })
+      const searchParams1 = {
+        sysTime: sysTime1,
+        lk: lk1
+      }
+      await this.$axios.get('/sysUserController/getCurrentUser', {params: searchParams1}).then((res) => {
+        user = res.data.sysUser
         // 用户信息+菜单权限加密存储
         let encryptUserInfo = userinfoEncrypt(JSON.stringify(res.data))
-        sessionStorage.setItem('active',encryptUserInfo)
-        if (user.lastUpdatePwdTime==null){
+        sessionStorage.setItem('active', encryptUserInfo)
+        if (user.lastUpdatePwdTime == null) {
           this.$message({
             type: 'warning',
             message: '需要修改初始密码!'
           });
           this.$router.push("/user/profile")
-        }
-        else{
+        } else {
           var dateBegin = new Date(user.lastUpdatePwdTime);
           var dateEnd = new Date();
           var dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数
           var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数
-          if (dayDiff>=30){
+          if (dayDiff >= 30) {
             this.$message({
               type: 'warning',
               message: '密码超过30天需要修改!'
@@ -199,6 +210,30 @@ export default {
         this.$message.error('获取当前用户数据出错' + error)
       })
 
+      let sysTime2
+      let lk2
+      await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
+        sysTime2 = res.data.sysTime
+        lk2 = res.data.lk
+      }).catch((error) => {
+      })
+      const searchParams2 = {
+        sysTime: sysTime2,
+        lk: lk2
+      }
+      // 检测用户密码是否符合要求
+      await this.$axios.get('/sysUserController/validatePasswordRule', {params: searchParams2}).then((res) => {
+        if (res.data != 'true'){
+          this.$message({
+            type: 'warning',
+            message: '密码规则不符合当前系统设定,请重新修改密码!'+res.data
+          })
+          this.$router.push("/user/profile")
+        }
+      }).catch((error) => {
+        this.$message.error('检测密码规则出错' + error)
+      })
+
       let sysTime
       let lk
       await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
@@ -212,12 +247,12 @@ export default {
         sysTime: sysTime,
         lk: lk
       }
-      await this.$axios.get('/sysUserController/getUserRole',{params: searchParams}).then((res) => {
+      await this.$axios.get('/sysUserController/getUserRole', {params: searchParams}).then((res) => {
         let userRole = res.data
-        if (userRole.roleId==1){
+        if (userRole.roleId == 1) {
           this.getAlarmData()
           // 系统管理员角色显示告警图标
-          this.alarmIconShow=true
+          this.alarmIconShow = true
           this.getAlarmData()
 
           // 取消定时刷新告警,无法实现用户非活动状态超时登出
@@ -228,9 +263,8 @@ export default {
           //     this.getAlarmData()
           //   }
           // }, 60000000)
-        }
-        else{
-          this.alarmIconShow=false
+        } else {
+          this.alarmIconShow = false
         }
 
       }).catch((error) => {
@@ -240,7 +274,7 @@ export default {
     /**
      * 删除提交
      */
-    readDone:debounce(async function(row){
+    readDone: debounce(async function (row) {
       let sysTime
       let lk
       await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
@@ -272,13 +306,13 @@ export default {
           message: '查收失败!'
         });
       })
-    },1000),
+    }, 1000),
     // 取消按钮
     cancel() {
       this.getAlarmData()
       this.open = false
     },
-    async getAlarmData(){
+    async getAlarmData() {
       let sysTime
       let lk
       await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
@@ -292,13 +326,12 @@ export default {
       }
       this.loading = true
       // 查询告警消息
-      await this.$axios.get('/sysAlarmController/getAll',{params: searchParams}).then((res) => {
+      await this.$axios.get('/sysAlarmController/getAll', {params: searchParams}).then((res) => {
         this.alarmList = res.data
-        if (res.data.length>0){
+        if (res.data.length > 0) {
           // 改变消息图标
           this.isMessage = true;
-        }
-        else{
+        } else {
           this.isMessage = false;
         }
         this.loading = false
@@ -307,7 +340,7 @@ export default {
         // this.$message.error(error)
       })
     },
-    showAlarm(){
+    showAlarm() {
       this.open = true
     },
     toggleSideBar() {
@@ -315,7 +348,7 @@ export default {
     },
     async logout() {
       this.$axios.post(
-        '/logout',{}
+        '/logout', {}
       ).then((res) => {
         this.$message.success(res.data)
         removeToken()
@@ -339,20 +372,22 @@ export default {
 
 <style lang="scss" scoped>
 .right-menu-item1 {
-  position:relative;
-  top:-15px;
+  position: relative;
+  top: -15px;
   font-size: 18px;
 }
-.item{
-  margin-tip:5px;
-  margin-right:15px;
+
+.item {
+  margin-tip: 5px;
+  margin-right: 15px;
 }
+
 .navbar {
   height: 50px;
   overflow: hidden;
   position: relative;
   background: #fff;
-  box-shadow: 0 1px 4px rgba(0,21,41,.08);
+  box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
 
   .hamburger-container {
     line-height: 46px;
@@ -360,7 +395,7 @@ export default {
     float: left;
     cursor: pointer;
     transition: background .3s;
-    -webkit-tap-highlight-color:transparent;
+    -webkit-tap-highlight-color: transparent;
 
     &:hover {
       background: rgba(0, 0, 0, .025)
@@ -439,7 +474,8 @@ export default {
       font-size: 18px;
       color: #5a5e66;
       vertical-align: text-bottom;
-      top:0px;
+      top: 0px;
+
       &.hover-effect1 {
         cursor: pointer;
         transition: background .3s;

+ 28 - 2
ui/src/permission.js

@@ -6,6 +6,7 @@ import 'nprogress/nprogress.css' // progress bar style
 import { getBrowserToken } from './utils/commonFuc' // get token from cookie
 import getPageTitle from '@/utils/get-page-title'
 import {doEncrypt, doDecryptStr,doSign,doVerifySignature,userinfoEncrypt,userinfoDecrypt} from '@/utils/smutil'
+import service from './utils/request'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
@@ -60,8 +61,33 @@ router.beforeEach(async (to, from, next) => {
             })
             next({ path: '/user/profile' })
           }
-          else{
-            next()
+          else {
+            let sysTime2
+            let lk2
+            await service.get('/sysPolicyController/getLicenseKey').then((res) => {
+              sysTime2 = res.data.sysTime
+              lk2 = res.data.lk
+            }).catch((error) => {
+            })
+            const searchParams2 = {
+              sysTime: sysTime2,
+              lk: lk2
+            }
+            // 检测用户密码是否符合要求
+            await service.get('/sysUserController/validatePasswordRule', {params: searchParams2}).then((res) => {
+              if (res.data != 'true'){
+                Message({
+                  type: 'warning',
+                  message: '密码规则不符合当前系统设定,请重新修改密码!'+res.data
+                })
+                next({ path: '/user/profile' })
+              }
+              else{
+                next()
+              }
+            }).catch((error) => {
+              this.$message.error('检测密码规则出错' + error)
+            })
           }
         }
       }

+ 15 - 3
ui/src/store/modules/permission.js

@@ -4,6 +4,7 @@ import Layout from '@/layout/index'
 import ParentView from '@/components/ParentView'
 import InnerLink from '@/layout/components/InnerLink'
 import request from '@/utils/request'
+import service from "@/utils/request";
 
 const permission = {
   state: {
@@ -33,10 +34,21 @@ const permission = {
   },
   actions: {
     // 生成路由
-    GenerateRoutes({ commit }) {
-      return new Promise((resolve,reject) => {
+     GenerateRoutes({ commit }) {
+      return new Promise(async (resolve,reject) => {
+        let sysTime2
+        let lk2
+        await service.get('/sysPolicyController/getLicenseKey').then((res) => {
+          sysTime2 = res.data.sysTime
+          lk2 = res.data.lk
+        }).catch((error) => {
+        })
+        const searchParams2 = {
+          sysTime: sysTime2,
+          lk: lk2
+        }
         // 向后端请求路由数据
-        request.get('/getRouters').then((res) => {
+        await request.get('/getRouters', {params: searchParams2}).then((res) => {
           const sdata = JSON.parse(JSON.stringify(res.data))
           const rdata = JSON.parse(JSON.stringify(res.data))
           const sidebarRoutes = filterAsyncRouter(sdata)

+ 23 - 1
ui/src/views/sysManager/sysPolicy/index.vue

@@ -7,6 +7,11 @@
           <el-form-item label="登录失败锁定时长(至少20分钟)" prop="loginLock">
             <el-input v-model="form.loginLock" style="width: 240px"></el-input>
           </el-form-item>
+          <el-form-item label="密码规则设置">
+            <el-checkbox-group v-model="form.passwordRule">
+              <el-checkbox v-for="(item,index) in passwordRuleList" :key="index" :label="item.value" >{{item.label}}</el-checkbox>
+            </el-checkbox-group>
+          </el-form-item>
           <el-form-item label="扫描未使用的账号(设定月个数)" prop="scanAccount">
             <el-input v-model="form.scanAccount" style="width: 240px"></el-input>
           </el-form-item>
@@ -74,6 +79,12 @@ import {debounce} from "lodash";
 export default {
   data() {
     return {
+      passwordRuleList: [
+        {value: 'A', label: '大写字母'},
+        {value: 'B', label: '小写字母'},
+        {value: 'C', label: '数字'},
+        {value: 'D', label: '特殊字符'},
+      ],
       excNoticeOptions: [
         {value: '0', label: '邮件'},
         {value: '1', label: '告警'}
@@ -94,6 +105,7 @@ export default {
         excNoticeWayB: '0',
         excLevelLogin: "0",
         excLevelSameUser: '0',
+        passwordRule: ''
       },
       // 表单校验
       rules: {
@@ -147,6 +159,7 @@ export default {
       }
       await this.$axios.get('/sysPolicyController/getAll',{params: searchParams}).then((res) => {
         this.form = res.data
+        this.form.passwordRule = res.data.passwordRule.split(',')
       }).catch((error) => {
         // this.$message.error(error)
       })
@@ -154,6 +167,14 @@ export default {
     onSubmit:debounce(async function(){
       this.$refs["form"].validate(async valid => {
         if (valid) {
+          if (this.form.passwordRule.length<3){
+            this.$message.warning('密码规则至少需要3种以上的组合!')
+            return
+          }
+          else{
+            this.form.passwordRule = this.form.passwordRule.join(",")
+          }
+
           let sysTime
           let lk
           await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {
@@ -161,9 +182,9 @@ export default {
             lk = res.data.lk
           }).catch((error) => {
           })
+
           this.form.sysTime = sysTime
           this.form.lk = lk
-
           this.loading = true
           await this.$axios.post('/sysPolicyController', this.form).then((res) => {
             if (res.code == 0) {
@@ -173,6 +194,7 @@ export default {
               this.$message.error(res.data)
             }
             this.loading = false
+            this.getList()
           }).catch((error) => {
             this.$message.error(error)
             this.loading = false

+ 41 - 41
ui/src/views/sysManager/userManager/profile/resetPwd.vue

@@ -52,19 +52,19 @@ export default {
         ]
       },
       //字母连续规则
-      strReg : /(a(?=b)|b(?=c)|c(?=d)|d(?=e)|e(?=f)|f(?=g)|g(?=h)|h(?=i)|i(?=j)|j(?=k)|k(?=l)|l(?=m)|m(?=n)|n(?=o)|o(?=p)|p(?=q)|q(?=r)|r(?=s)|s(?=t)|t(?=u)|u(?=v)|v(?=w)|w(?=x)|x(?=y)|y(?=z)|z(?=a)){3}[a-z]/i,
-      strResverReg : /(a(?=z)|z(?=y)|y(?=x)|x(?=w)|w(?=v)|v(?=u)|u(?=t)|t(?=s)|s(?=r)|r(?=q)|q(?=p)|p(?=o)|o(?=n)|n(?=m)|m(?=l)|l(?=k)|k(?=j)|j(?=i)|i(?=h)|h(?=g)|g(?=f)|f(?=e)|e(?=d)|d(?=c)|c(?=b)|b(?=a)){3}[a-z]/i,
+      // strReg : /(a(?=b)|b(?=c)|c(?=d)|d(?=e)|e(?=f)|f(?=g)|g(?=h)|h(?=i)|i(?=j)|j(?=k)|k(?=l)|l(?=m)|m(?=n)|n(?=o)|o(?=p)|p(?=q)|q(?=r)|r(?=s)|s(?=t)|t(?=u)|u(?=v)|v(?=w)|w(?=x)|x(?=y)|y(?=z)|z(?=a)){3}[a-z]/i,
+      // strResverReg : /(a(?=z)|z(?=y)|y(?=x)|x(?=w)|w(?=v)|v(?=u)|u(?=t)|t(?=s)|s(?=r)|r(?=q)|q(?=p)|p(?=o)|o(?=n)|n(?=m)|m(?=l)|l(?=k)|k(?=j)|j(?=i)|i(?=h)|h(?=g)|g(?=f)|f(?=e)|e(?=d)|d(?=c)|c(?=b)|b(?=a)){3}[a-z]/i,
       //数字连续规则
-      numReg : /(0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)|9(?=0)){3}\d/,
-      numResverReg : /(0(?=9)|9(?=8)|8(?=7)|7(?=6)|6(?=5)|5(?=4)|4(?=3)|3(?=2)|2(?=1)|1(?=0)){3}\d/,
+      // numReg : /(0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)|9(?=0)){3}\d/,
+      // numResverReg : /(0(?=9)|9(?=8)|8(?=7)|7(?=6)|6(?=5)|5(?=4)|4(?=3)|3(?=2)|2(?=1)|1(?=0)){3}\d/,
       //键盘字母横向连续规则
-      keyboardHorizontalReg : /(q(?=w)|w(?=e)|e(?=r)|r(?=t)|t(?=y)|y(?=u)|u(?=i)|i(?=o)|o(?=p)|p(?=q)|a(?=s)|s(?=d)|d(?=f)|f(?=g)|g(?=h)|h(?=j)|j(?=k)|k(?=l)|l(?=a)|z(?=x)|x(?=c)|c(?=v)|v(?=b)|b(?=n)|n(?=m)|m(?=z)){3}[a-z]/i,
-      keyboardHorizontalResverReg : /(p(?=o)|o(?=i)|i(?=u)|u(?=y)|y(?=t)|t(?=r)|r(?=e)|e(?=w)|w(?=q)|q(?=p)|l(?=k)|k(?=j)|j(?=h)|h(?=g)|g(?=f)|f(?=d)|d(?=s)|s(?=a)|a(?=l)|m(?=n)|n(?=b)|b(?=v)|v(?=c)|c(?=x)|x(?=z)|z(?=m)){3}[a-z]/i,
+      // keyboardHorizontalReg : /(q(?=w)|w(?=e)|e(?=r)|r(?=t)|t(?=y)|y(?=u)|u(?=i)|i(?=o)|o(?=p)|p(?=q)|a(?=s)|s(?=d)|d(?=f)|f(?=g)|g(?=h)|h(?=j)|j(?=k)|k(?=l)|l(?=a)|z(?=x)|x(?=c)|c(?=v)|v(?=b)|b(?=n)|n(?=m)|m(?=z)){3}[a-z]/i,
+      // keyboardHorizontalResverReg : /(p(?=o)|o(?=i)|i(?=u)|u(?=y)|y(?=t)|t(?=r)|r(?=e)|e(?=w)|w(?=q)|q(?=p)|l(?=k)|k(?=j)|j(?=h)|h(?=g)|g(?=f)|f(?=d)|d(?=s)|s(?=a)|a(?=l)|m(?=n)|n(?=b)|b(?=v)|v(?=c)|c(?=x)|x(?=z)|z(?=m)){3}[a-z]/i,
       //多个相同字母、数字规则
-      sameReg : /([0-9a-zA-Z])\1{3}/,
-      keyboardSlopeArr : ["1qaz", "2wsx", "3edc", "4rfv", "5tgb", "6yhn", "7ujm", "8ik,", "9ol.", "0p;/", "/;p0", ".lo9", ",ki8", "mju7", "nhy6", "bgt5", "vfr4", "cde3", "xsw2", "zaq1", "4esz", "5rdx", "6tfc", "7ygv", "8uhb", "9ijn", "0okm", "-pl,", "=[;.", ".;[=", ",lp-", "mko0", "nji9", "bhu8", "vgy7", "cft6", "xdr5", "zse4"],
-      keyboardSlopeShiftArr : ["!qaz", "@wsx", "#edc","$rfv", "%tgb", "^yhn", "&ujm", "*ik<", "(ol>", ")p:?", "?:p)", ">lo(", "<ki*", "mju&", "nhy^", "bgt%", "vfr$", "cde#", "xsw@", "zaq!", "$esz", "%rdx", "^tfc", "&ygv", "*uhb", "(ijn", ")okm", "_pl<", "+{:>", ">:{+", "<lp_", "mko)", "nji(", "bhu*", "vgy&", "cft^", "xdr%", "zse$"],
-      lastReg: /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_!@#$%^&*`~()-+=]+$)(?![a-z0-9]+$)(?![a-z\W_!@#$%^&*`~()-+=]+$)(?![0-9\W_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9\W_!@#$%^&*`~()-+=]{8,20}$/
+      // sameReg : /([0-9a-zA-Z])\1{3}/,
+      // keyboardSlopeArr : ["1qaz", "2wsx", "3edc", "4rfv", "5tgb", "6yhn", "7ujm", "8ik,", "9ol.", "0p;/", "/;p0", ".lo9", ",ki8", "mju7", "nhy6", "bgt5", "vfr4", "cde3", "xsw2", "zaq1", "4esz", "5rdx", "6tfc", "7ygv", "8uhb", "9ijn", "0okm", "-pl,", "=[;.", ".;[=", ",lp-", "mko0", "nji9", "bhu8", "vgy7", "cft6", "xdr5", "zse4"],
+      // keyboardSlopeShiftArr : ["!qaz", "@wsx", "#edc","$rfv", "%tgb", "^yhn", "&ujm", "*ik<", "(ol>", ")p:?", "?:p)", ">lo(", "<ki*", "mju&", "nhy^", "bgt%", "vfr$", "cde#", "xsw@", "zaq!", "$esz", "%rdx", "^tfc", "&ygv", "*uhb", "(ijn", ")okm", "_pl<", "+{:>", ">:{+", "<lp_", "mko)", "nji(", "bhu*", "vgy&", "cft^", "xdr%", "zse$"],
+      // lastReg: /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_!@#$%^&*`~()-+=]+$)(?![a-z0-9]+$)(?![a-z\W_!@#$%^&*`~()-+=]+$)(?![0-9\W_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9\W_!@#$%^&*`~()-+=]{8,20}$/
     };
   },
   methods: {
@@ -80,37 +80,37 @@ export default {
       this.$refs["form"].validate(async valid => {
         if (valid) {
           // 密码验证规则
-          if (this.sameReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不能含有连续4位相同的数字或字母')
-            return
-          } else if (this.strResverReg.test(this.pwd.newPassword.toLowerCase())) {
-            this.$message.error('密码不能含有4位连续的字母')
-            return
-          } else if (this.strReg.test(this.pwd.newPassword.toLowerCase())) {
-            this.$message.error('密码不能含有4位连续的字母')
-            return
-          } else if (this.numReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不能含有4位连续的数字')
-            return
-          } else if (this.numResverReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不能含有4位连续的数字')
-            return
-          } else if (this.keyboardHorizontalReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不能含有4位横向连续的字母')
-            return
-          } else if (this.keyboardHorizontalResverReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不能含有4位横向连续的字母')
-            return
-          } else if (this.keyboardSlopeArr.some(v => this.pwd.newPassword.toLowerCase().indexOf(v) > -1)) {
-            this.$message.error('密码不能含有4位键盘斜向连续的字符')
-            return
-          } else if (this.keyboardSlopeShiftArr.some(v => this.pwd.newPassword.toLowerCase().indexOf(v) > -1)) {
-            this.$message.error('密码不能含有4位键盘斜向连续的字符')
-            return
-          } else if (!this.lastReg.test(this.pwd.newPassword)) {
-            this.$message.error('密码不满足8~20位大写字母、小写字母、数字、特殊字符三种以上的组合')
-            return
-          }
+          // if (this.sameReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不能含有连续4位相同的数字或字母')
+          //   return
+          // } else if (this.strResverReg.test(this.pwd.newPassword.toLowerCase())) {
+          //   this.$message.error('密码不能含有4位连续的字母')
+          //   return
+          // } else if (this.strReg.test(this.pwd.newPassword.toLowerCase())) {
+          //   this.$message.error('密码不能含有4位连续的字母')
+          //   return
+          // } else if (this.numReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不能含有4位连续的数字')
+          //   return
+          // } else if (this.numResverReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不能含有4位连续的数字')
+          //   return
+          // } else if (this.keyboardHorizontalReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不能含有4位横向连续的字母')
+          //   return
+          // } else if (this.keyboardHorizontalResverReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不能含有4位横向连续的字母')
+          //   return
+          // } else if (this.keyboardSlopeArr.some(v => this.pwd.newPassword.toLowerCase().indexOf(v) > -1)) {
+          //   this.$message.error('密码不能含有4位键盘斜向连续的字符')
+          //   return
+          // } else if (this.keyboardSlopeShiftArr.some(v => this.pwd.newPassword.toLowerCase().indexOf(v) > -1)) {
+          //   this.$message.error('密码不能含有4位键盘斜向连续的字符')
+          //   return
+          // } else if (!this.lastReg.test(this.pwd.newPassword)) {
+          //   this.$message.error('密码不满足8~20位大写字母、小写字母、数字、特殊字符三种以上的组合')
+          //   return
+          // }
           let sysTime
           let lk
           await this.$axios.get('/sysPolicyController/getLicenseKey').then((res) => {