Browse Source

增加审计日志定时备份

xusl 2 năm trước cách đây
mục cha
commit
08d224a579

+ 285 - 0
backend/src/main/java/com/jiayue/ssi/job/AutoAuditBak.java

@@ -0,0 +1,285 @@
+package com.jiayue.ssi.job;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.csv.CsvUtil;
+import cn.hutool.core.text.csv.CsvWriter;
+import cn.hutool.core.util.CharsetUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jiayue.ssi.constant.SecretKeyConstants;
+import com.jiayue.ssi.entity.*;
+import com.jiayue.ssi.entity.server.Jvm;
+import com.jiayue.ssi.service.SysAlarmService;
+import com.jiayue.ssi.service.SysLogininforService;
+import com.jiayue.ssi.service.SysOperLogService;
+import com.jiayue.ssi.service.SysPolicyService;
+import com.jiayue.ssi.util.DateUtils;
+import com.jiayue.ssi.util.FileUtil;
+import com.jiayue.ssi.util.ResponseVO;
+import com.jiayue.ssi.util.SM2CryptUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+* 自动备份审计日志
+*
+* @author xsl
+* @since 2023/04/06
+*/
+@Service
+@EnableScheduling
+@Slf4j
+public class AutoAuditBak {
+    @Autowired
+    SysLogininforService sysLogininforService;
+    @Autowired
+    SysPolicyService sysPolicyService;
+    @Autowired
+    SysOperLogService sysOperLogService;
+
+    /**
+     * 每30分钟执行一次扫描
+     */
+    @Scheduled(cron = "0 0/1 * * * ?")
+    public void auditBak() throws Exception{
+        SysPolicy sysPolicy = sysPolicyService.getOne(new QueryWrapper<>());
+        // 保留月份数
+        int auditLog = sysPolicy.getAuditLog();
+        // 先获取要备份截止时间点
+        Calendar calendar = Calendar.getInstance(); //创建Calendar 的实例
+        calendar.add(Calendar.MONTH, -(auditLog+1));//当前时间减去一个月,即一个月前的时间
+        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));//获取月份最后一天
+        try {
+            // 登录日志备份
+            createSysLogininforCsvFile(calendar);
+        }
+        catch (Exception e){
+            log.error("登录日志备份出错",e);
+        }
+        try {
+            // 操作日志备份
+            createSysOperCsvFile(calendar);
+        }
+        catch (Exception e){
+            log.error("操作日志备份出错",e);
+        }
+    }
+
+    /**
+     * 生成登录日志csv文件
+     *
+     * @param calendar      备份截止时间
+     */
+    public void createSysLogininforCsvFile(Calendar calendar) throws Exception{
+        log.info("执行登录日志备份");
+        QueryWrapper<SysLogininfor> sysLogininforQueryWrapper = new QueryWrapper<>();
+        sysLogininforQueryWrapper.le("create_time", DateUtils.getDayLastTime(calendar.getTime()));
+        List<SysLogininfor> sysLogininforList = sysLogininforService.list(sysLogininforQueryWrapper);
+        // 生成csv备份
+        if (sysLogininforList.size()>0){
+            // 备份文件名
+            String fileName = DateUtil.format(DateUtils.getDayLastTime(calendar.getTime()),"yyyy-MM-dd") + "-" + "SysLogininfor" + ".csv";
+            //第一行
+            String[] listName = new String[15];
+            listName[0] = "infoId";
+            listName[1] = "userName";
+            listName[2] = "status";
+            listName[3] = "ipaddr";
+            listName[4] = "loginLocation";
+            listName[5] = "browser";
+            listName[6] = "os";
+            listName[7] = "msg";
+            listName[8] = "loginTime";
+            listName[9] = "delFlag";
+            listName[10] = "createBy";
+            listName[11] = "createTime";
+            listName[12] = "updateBy";
+            listName[13] = "updateTime";
+            listName[14] = "remark";
+            //获取String[]类型的数据至result中
+            List<String> result = new ArrayList<>();
+            String listNameStr = "";
+            for (int i=0;i<listName.length;i++){
+                listNameStr = listNameStr + listName[i]+"|";
+            }
+            String headEncrypt = SM2CryptUtils.encrypt(listNameStr.substring(0,listNameStr.length()-1), SecretKeyConstants.CLIENT_PUBLIC_KEY);
+//            System.out.println("加密:"+headEncrypt);
+//            String headText = SM2CryptUtils.decrypt(headEncrypt,SecretKeyConstants.CLIENT_PRIVATE_KEY);
+//            System.out.println("解密:"+headText);
+            //将listName添加到result中
+            result.add(headEncrypt);
+            Long delIds[] = new Long[sysLogininforList.size()];
+            for (int j=0;j<sysLogininforList.size();j++) {
+                SysLogininfor sysLogininfor = sysLogininforList.get(j);
+                String[] listValue = new String[15];
+                listValue[0] = String.valueOf(sysLogininfor.getInfoId());
+                delIds[j] = sysLogininfor.getInfoId();
+                listValue[1] = String.valueOf(sysLogininfor.getUserName());
+                listValue[2] = String.valueOf(sysLogininfor.getStatus());
+                listValue[3] = String.valueOf(sysLogininfor.getIpaddr());
+                listValue[4] = String.valueOf(sysLogininfor.getLoginLocation());
+                listValue[5] = String.valueOf(sysLogininfor.getBrowser());
+                listValue[6] = String.valueOf(sysLogininfor.getOs());
+                listValue[7] = String.valueOf(sysLogininfor.getMsg());
+                listValue[8] = String.valueOf(DateUtil.format(sysLogininfor.getLoginTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[9] = String.valueOf(sysLogininfor.getDelFlag());
+                listValue[10] = String.valueOf(sysLogininfor.getCreateBy());
+                listValue[11] = String.valueOf(DateUtil.format(sysLogininfor.getCreateTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[12] = String.valueOf(sysLogininfor.getUpdateBy());
+                listValue[13] = String.valueOf(DateUtil.format(sysLogininfor.getUpdateTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[14] = String.valueOf(sysLogininfor.getRemark());
+
+                String listValueStr = "";
+                for (int k=0;k<listValue.length;k++){
+                    listValueStr = listValueStr + listValue[k]+"|";
+                }
+                String encrypt = SM2CryptUtils.encrypt(listValueStr.substring(0,listValueStr.length()-1), SecretKeyConstants.CLIENT_PUBLIC_KEY);
+//                System.out.println("加密:"+encrypt);
+//                String text = SM2CryptUtils.decrypt(encrypt,SecretKeyConstants.CLIENT_PRIVATE_KEY);
+//                System.out.println("解密:"+text);
+                result.add(encrypt);
+            }
+            //导入HuTool中CSV工具包的CsvWriter类
+            //设置导出字符类型, CHARSET_UTF_8
+            File csvFile = new File(fileName);
+            File destDir = new File(FileUtil.getAuditBackUpPath()+ File.separator +DateUtils.dateTime());
+            if (!destDir.exists()) {// 如果目录不存在则创建目录
+                boolean b = destDir.mkdirs();
+                if (!b) {
+                    throw new RuntimeException(destDir.getPath() + " 目录创建失败");
+                }
+            }
+            CsvWriter writer = CsvUtil.getWriter(destDir + File.separator + csvFile.getName(), CharsetUtil.CHARSET_UTF_8);
+            writer.write(result);  //通过CsvWriter中的write方法写入数据
+            writer.close();   //关闭CsvWriter
+            // 删除表中数据
+            sysLogininforService.deleteLogininforByIds(delIds);
+        }
+        log.info("结束登录日志备份");
+    }
+
+    /**
+     * 生成操作日志csv文件
+     *
+     * @param calendar      备份截止时间
+     */
+    public void createSysOperCsvFile(Calendar calendar) throws Exception{
+        log.info("执行登录日志备份");
+        QueryWrapper<SysOperLog> sysOperLogQueryWrapper = new QueryWrapper<>();
+        sysOperLogQueryWrapper.le("create_time", DateUtils.getDayLastTime(calendar.getTime()));
+        List<SysOperLog> sysOperLogList = sysOperLogService.list(sysOperLogQueryWrapper);
+        // 生成csv备份
+        if (sysOperLogList.size()>0){
+            // 备份文件名
+            String fileName = DateUtil.format(DateUtils.getDayLastTime(calendar.getTime()),"yyyy-MM-dd") + "-" + "SysOperLog" + ".csv";
+            //第一行
+            String[] listName = new String[25];
+            listName[0] = "operId";
+            listName[1] = "title";
+            listName[2] = "businessType";
+            listName[3] = "auditType";
+            listName[4] = "businessTypes";
+            listName[5] = "method";
+            listName[6] = "requestMethod";
+            listName[7] = "operatorType";
+            listName[8] = "operName";
+            listName[9] = "deptName";
+            listName[10] = "operUrl";
+            listName[11] = "operIp";
+            listName[12] = "operLocation";
+            listName[13] = "operParam";
+            listName[14] = "jsonResult";
+            listName[15] = "status";
+            listName[16] = "errorMsg";
+            listName[17] = "operTime";
+            listName[18] = "costTime";
+            listName[19] = "delFlag";
+            listName[20] = "createBy";
+            listName[21] = "createTime";
+            listName[22] = "updateBy";
+            listName[23] = "updateTime";
+            listName[24] = "remark";
+            //获取String[]类型的数据至result中
+            List<String> result = new ArrayList<>();
+            String listNameStr = "";
+            for (int i=0;i<listName.length;i++){
+                listNameStr = listNameStr + listName[i]+"|";
+            }
+            String headEncrypt = SM2CryptUtils.encrypt(listNameStr.substring(0,listNameStr.length()-1), SecretKeyConstants.CLIENT_PUBLIC_KEY);
+//            System.out.println("加密:"+headEncrypt);
+//            String headText = SM2CryptUtils.decrypt(headEncrypt,SecretKeyConstants.CLIENT_PRIVATE_KEY);
+//            System.out.println("解密:"+headText);
+            //将listName添加到result中
+            result.add(headEncrypt);
+            Long delIds[] = new Long[sysOperLogList.size()];
+            for (int j=0;j<sysOperLogList.size();j++) {
+                SysOperLog sysOperLog = sysOperLogList.get(j);
+                String[] listValue = new String[25];
+                listValue[0] = String.valueOf(sysOperLog.getOperId());
+                delIds[j] = sysOperLog.getOperId();
+                listValue[1] = String.valueOf(sysOperLog.getTitle());
+                listValue[2] = String.valueOf(sysOperLog.getBusinessType());
+                listValue[3] = String.valueOf(sysOperLog.getAuditType());
+                listValue[4] = String.valueOf(sysOperLog.getBusinessTypes());
+                listValue[5] = String.valueOf(sysOperLog.getMethod());
+                listValue[6] = String.valueOf(sysOperLog.getRequestMethod());
+                listValue[7] = String.valueOf(sysOperLog.getOperatorType());
+                listValue[8] = String.valueOf(sysOperLog.getOperName());
+                listValue[9] = String.valueOf(sysOperLog.getDeptName());
+                listValue[10] = String.valueOf(sysOperLog.getOperUrl());
+                listValue[11] = String.valueOf(sysOperLog.getOperIp());
+                listValue[12] = String.valueOf(sysOperLog.getOperLocation());
+                listValue[13] = String.valueOf(sysOperLog.getOperParam());
+                listValue[14] = String.valueOf(sysOperLog.getJsonResult());
+                listValue[15] = String.valueOf(sysOperLog.getStatus());
+                listValue[16] = String.valueOf(sysOperLog.getErrorMsg());
+                listValue[17] = String.valueOf(DateUtil.format(sysOperLog.getOperTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[18] = String.valueOf(sysOperLog.getCostTime());
+                listValue[19] = String.valueOf(sysOperLog.getDelFlag());
+                listValue[20] = String.valueOf(sysOperLog.getCreateBy());
+                listValue[21] = String.valueOf(DateUtil.format(sysOperLog.getCreateTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[22] = String.valueOf(sysOperLog.getUpdateBy());
+                listValue[23] = String.valueOf(DateUtil.format(sysOperLog.getUpdateTime(),"yyyy-MM-dd HH:mm:ss"));
+                listValue[24] = String.valueOf(sysOperLog.getRemark());
+
+                String listValueStr = "";
+                for (int k=0;k<listValue.length;k++){
+                    listValueStr = listValueStr + listValue[k]+"|";
+                }
+                String encrypt = SM2CryptUtils.encrypt(listValueStr.substring(0,listValueStr.length()-1), SecretKeyConstants.CLIENT_PUBLIC_KEY);
+//                System.out.println("加密:"+encrypt);
+//                String text = SM2CryptUtils.decrypt(encrypt,SecretKeyConstants.CLIENT_PRIVATE_KEY);
+//                System.out.println("解密:"+text);
+                result.add(encrypt);
+            }
+            //导入HuTool中CSV工具包的CsvWriter类
+            //设置导出字符类型, CHARSET_UTF_8
+            File csvFile = new File(fileName);
+            File destDir = new File(FileUtil.getAuditBackUpPath()+ File.separator +DateUtils.dateTime());
+            if (!destDir.exists()) {// 如果目录不存在则创建目录
+                boolean b = destDir.mkdirs();
+                if (!b) {
+                    throw new RuntimeException(destDir.getPath() + " 目录创建失败");
+                }
+            }
+            CsvWriter writer = CsvUtil.getWriter(destDir + File.separator + csvFile.getName(), CharsetUtil.CHARSET_UTF_8);
+            writer.write(result);  //通过CsvWriter中的write方法写入数据
+            writer.close();   //关闭CsvWriter
+            // 删除表中数据
+            sysOperLogService.deleteOperLogByIds(delIds);
+        }
+        log.info("结束操作日志备份");
+    }
+}

+ 8 - 0
backend/src/main/java/com/jiayue/ssi/service/SysLogininforService.java

@@ -2,6 +2,8 @@ package com.jiayue.ssi.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.jiayue.ssi.entity.SysLogininfor;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 
 
 /**
@@ -26,4 +28,10 @@ public interface SysLogininforService extends IService<SysLogininfor> {
      * 清空系统登录日志
      */
     boolean cleanLogininfor();
+    /**
+     * 批量真实删除登录日志
+     * @param infoIds 主键id集合
+     * @return
+     */
+    boolean deleteLogininforByIds(Long[] infoIds);
 }

+ 6 - 0
backend/src/main/java/com/jiayue/ssi/service/SysOperLogService.java

@@ -29,4 +29,10 @@ public interface SysOperLogService extends IService<SysOperLog> {
      * 清空操作日志
      */
     boolean cleanOperLog();
+    /**
+     * 批量真实删除操作日志
+     * @param operIds 主键id集合
+     * @return
+     */
+    boolean deleteOperLogByIds(Long[] operIds);
 }

+ 14 - 0
backend/src/main/java/com/jiayue/ssi/service/impl/SysLogininforServiceImpl.java

@@ -66,4 +66,18 @@ public class SysLogininforServiceImpl  extends ServiceImpl<SysLogininforMapper,
         }
         return false;
     }
+    /**
+     * 批量真实删除登录日志
+     * @param infoIds 主键id集合
+     * @return
+     */
+    @Override
+    @Transactional(propagation= Propagation.REQUIRED, rollbackFor = Exception.class)
+    public boolean deleteLogininforByIds(Long[] infoIds) {
+        int count = logininforMapper.deleteLogininforByIds(infoIds);
+        if (count > 0) {
+            return  true;
+        }
+        return false;
+    }
 }

+ 14 - 0
backend/src/main/java/com/jiayue/ssi/service/impl/SysOperLogServiceImpl.java

@@ -62,4 +62,18 @@ public class SysOperLogServiceImpl  extends ServiceImpl<SysOperLogMapper, SysOpe
         }
         return false;
     }
+    /**
+     * 批量真实删除操作日志
+     * @param operIds 主键id集合
+     * @return
+     */
+    @Override
+    @Transactional(propagation= Propagation.REQUIRED, rollbackFor = Exception.class)
+    public boolean deleteOperLogByIds(Long[] operIds) {
+        int count = operLogMapper.deleteOperLogByIds(operIds);
+        if (count > 0) {
+            return  true;
+        }
+        return false;
+    }
 }

+ 141 - 0
backend/src/main/java/com/jiayue/ssi/util/FileUtil.java

@@ -0,0 +1,141 @@
+package com.jiayue.ssi.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.springframework.util.ResourceUtils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Date;
+
+/**
+ * 文件工具类
+ *
+ * @author xsl
+ * @version 3.0
+ */
+@Slf4j
+public class FileUtil {
+  /**
+   * 移动本地文件
+   *
+   * @param remoteAbsoluteFile 远程文件名(包括完整路径)
+   * @param localAbsoluteFile  本地文件名(包括完整路径)
+   * @return 成功时,返回true,失败返回false
+   * @throws Exception
+   */
+  public static void move(String localAbsoluteFile, String remoteAbsoluteFile) throws Exception {
+    File srcFile = new File(localAbsoluteFile);
+    File destDir = new File(remoteAbsoluteFile);
+    try {
+      if (!destDir.exists()) {// 如果目录不存在则创建目录
+        boolean b = destDir.mkdirs();
+        if (!b) {// 如果创建失败则抛出异常
+          throw new RuntimeException(destDir + " 目录创建失败");
+        }
+      }
+      FileUtils.moveFile(srcFile, new File(remoteAbsoluteFile + File.separator + srcFile.getName()));
+    } catch (IOException e) {
+      throw new Exception("文件:" + srcFile.getName() + "移动到" + destDir.getPath() + "失败。", e);
+    }
+  }
+
+  /**
+   * 获取文件创建时间
+   *
+   * @param fullFileName
+   * @return
+   */
+  public static Long getFileCreateTime(String fullFileName) {
+    Path path = Paths.get(fullFileName);
+    BasicFileAttributeView basicview = Files.getFileAttributeView(path, BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
+    BasicFileAttributes attr;
+    try {
+      attr = basicview.readAttributes();
+      Date createDate = new Date(attr.creationTime().toMillis());
+      return createDate.getTime();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return System.currentTimeMillis();
+  }
+
+  /**
+   * 获取项目根路径
+   *
+   * @return
+   */
+  public static String getResourceBasePath() {
+    // 获取跟目录
+    File path = null;
+    try {
+      path = new File(ResourceUtils.getURL("classpath:").getPath());
+
+    } catch (FileNotFoundException e) {
+      // nothing to do
+    }
+    if (path == null || !path.exists()) {
+      path = new File("");
+    }
+
+    String pathStr = path.getAbsolutePath();
+    try {
+      pathStr = URLDecoder.decode(pathStr, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      e.printStackTrace();
+    }
+    // 如果是在eclipse中运行,则和target同级目录,如果是jar部署到服务器,则默认和jar包同级
+//    pathStr = pathStr.replace("\\target\\classes", "");
+
+    return pathStr;
+  }
+
+  /**
+   * 获取日志目录路径
+   *
+   * @return
+   */
+  public static String getLogsPath() {
+    return createDir("ssiLogs");
+  }
+  /**
+   * 获取升级日志备份目录路径
+   *
+   * @return
+   */
+  public static String getAuditBackUpPath() {
+    return createDir("auditBak");
+  }
+
+  private static String createDir(String dir) {
+    String path = "";
+    if (System.getProperties().getProperty("file.separator").equals("\\")) {
+      path = new File(getResourceBasePath()).getParentFile().getParentFile().getParentFile().getAbsolutePath() + File.separator + dir;
+      try {
+        path = URLDecoder.decode(path, "UTF-8");
+      } catch (UnsupportedEncodingException e) {
+        e.printStackTrace();
+      }
+      File file = new File(path);
+      if (!file.exists()) {
+        boolean b = file.mkdirs();
+        if (!b) {
+          log.error("目录创建失败" + path);
+        }
+      }
+    }
+    else{
+      path = "/home/syjy/ssi/"+ dir;
+    }
+    return path;
+  }
+}

+ 4 - 0
backend/src/main/resources/mapper/system/SysLogininforMapper.xml

@@ -60,4 +60,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         truncate table sys_logininfor
     </update>
 
+	<select id="selectBackUpList" parameterType="Long" resultMap="SysLogininforResult">
+		select * from sys_logininfor where create_time &lt;= #{createTime}
+		order by createTime desc
+	</select>
 </mapper>

+ 7 - 4
ui/src/permission.js

@@ -14,13 +14,12 @@ const whiteList = ['/login'] // no redirect whitelist
 router.beforeEach(async (to, from, next) => {
   // start progress bar
   NProgress.start()
-
   // set page title
   document.title = getPageTitle(to.meta.title)
   if (sessionStorage.getItem('token')) {
     if (to.path === '/login') {
       // if is logged in, redirect to the home page
-      next({ path: '/' })
+      next({ path: '/dashboard' })
       NProgress.done()
     } else {
       // 登录成功时将路由置空
@@ -32,7 +31,7 @@ router.beforeEach(async (to, from, next) => {
         }).catch(err => {
           store.dispatch('changeRouters',[])
           console.log('生成路由异常,输出routes:'+store.getters.permission_routes.length)
-          next({ path: '/' })
+          next({ path: '/dashboard' })
         })
       }
 
@@ -76,10 +75,14 @@ router.beforeEach(async (to, from, next) => {
       // 在免登录白名单,直接进入
       next()
     } else {
-      if (to.path === '/404') {
+      if (to.path === '/') {
+        next('/login')
+        NProgress.done()
+      }else if (to.path === '/404') {
         next()
       }
       else{
+        alert(to.path)
         // 否则全部重定向到登录页
         next(`/login?redirect=${to.path}`)
         NProgress.done()

+ 2 - 2
ui/src/router/index.js

@@ -42,11 +42,11 @@ export const constantRoutes = [
     hidden: true
   },
   {
-    path: '/',
+    path: '',
     component: Layout,
     redirect: '/dashboard',
     children: [{
-      path: 'dashboard',
+      path: '/dashboard',
       name: '首页',
       component: () => import('@/views/dashboard/index'),
       meta: {title: '首页', icon: 'dashboard', affix: true}

+ 0 - 1
ui/src/utils/request.js

@@ -84,7 +84,6 @@ service.interceptors.response.use(
    * You can also judge the status by HTTP Status Code
    */
   response => {
-    console.log("===================")
     const res = response.data
     let returnStr = res.split("&")
     let returnData = returnStr[0].split("=")[1]

+ 1 - 1
ui/src/views/login/index.vue

@@ -261,7 +261,7 @@ export default {
             sessionStorage.setItem('token', tokenStr+'&'+sign)
             // 清空路由菜单
             store.commit('SET_R', [])
-            this.$router.push('/')
+            this.$router.push('/dashboard')
             this.loading = false
           }).catch((error) => {
             // 登录失败刷新验证码