问题形容

产品说,出于平安思考,用户长时间不操作,就回到登录页面,让用户从新登录,就像银行的app一样。本文就记录一下实现这种成果的两种形式,别离是前端管制和后端管制,各有细节及实用应用场景

前端管制(形式一)

思路

首先,用户长时间不操作具体表现形式是啥?其实就是事件是否长时间没有被触发执行。

比方用户长时间不操作,就没有鼠标点击(click)事件、鼠标滚轮(mousewheel)事件、鼠标挪动(mousemove)事件之类的,咱们只须要监听这些事件,如果这些事件长时间没有触发,就阐明用户长时间未操作,而后路由跳转到登录页面即可。

这三个事件我抉择的是比拟实用的鼠标点击事件,咱们晓得,一般来说我的项目的第一个页面是登录页面,所以在登录页面用户点击登录按钮的时候,就记录一下点击登录按钮的工夫,存储到sessionstorage中去,当跳转到主页面的时候,当用户每点击一次页面,就更新一下sessionstorage中的存储的工夫,同时也给页面绑定一个循环定时器,距离一段时间就把以后工夫和sessionstorage贮存的上一次点击事件的工夫做一个差值比照,当差值超过肯定工夫,就强制用户退出到登录页面即可。

代码

login.vue页面

// html<el-button type="primary" @click="loginIn">点击登录</el-button>// jsmethods: {    loginIn() {      // 存第一份点击的工夫      sessionStorage.setItem("lastClickTime", new Date().getTime());      // 模仿后端返回存一个token      sessionStorage.setItem('token',"token")      this.$router.push({        path: "/",      });    },}

Home.vue页面

<template>  <div class="homeBox">    <!-- 右边是菜单层级 -->    <div class="left">      <div class="leftNav">        <el-menu          :default-active="activeIndex"          class="elMenu"          background-color="#333"          text-color="#B0B0B2"          active-text-color="#fff"          :unique-opened="true"          router          ref="elMenu"        >          <el-menu-item index="/vue">            <i class="el-icon-location-outline"></i>            <span slot="title">vue页面</span>          </el-menu-item>          <el-menu-item index="/react">            <i class="el-icon-star-off"></i>            <span slot="title">react页面</span>          </el-menu-item>          <el-menu-item index="/angular">            <i class="el-icon-pear"></i>            <span slot="title">angular页面</span>          </el-menu-item>        </el-menu>      </div>    </div>    <!-- 左边是视图层级 -->    <div class="right">      <div class="rightTop">        <el-button type="primary" plain @click="loginOut">登出</el-button>      </div>      <div class="rightBottom">        <router-view></router-view>      </div>    </div>  </div></template><script>export default {  name: "Home",  data() {    return {      activeIndex: this.$route.path,      timer: null,    };  },  created() {    /*       第一步:        组件初始化加载就绑定监听点击事件,留神:addEventListener的第三个参数,这里要加上。        因为第三个参数决定了是冒泡还是捕捉(false冒泡默认,true捕捉),因为绑定监听点击事件,咱们是在最        顶层的DOM地位进行捕捉点击事件,所以第三个参数true,要加上的,这样的话,内层的任意中央的点击事件        咱们就都能监听到了,而后存储一下点击的工夫    */    window.addEventListener(      "click",      () => {        // 为了不便,咱们把点击事件的工夫间接存到sessionStorage中去,这样不便获取比拟        sessionStorage.setItem("lastClickTime", new Date().getTime());      },      true    );  },  mounted() {    /*      第二步:        组件初始化加载时也要绑定一个定时器,通过定时器定时轮询,去比照以后工夫和上次点击的工夫的差值    */    this.isTimeOut();  },  methods: {    isTimeOut() {      // 应用定时器之前,要革除一下定时器      clearInterval(this.timer);      this.timer = setInterval(() => {        let lastClickTime = sessionStorage.getItem("lastClickTime") * 1; // 把上次点击时候的字符串工夫转换成数字工夫        let nowTime = new Date().getTime(); // 获取以后工夫        console.log("以后工夫和之前点击工夫", nowTime, lastClickTime);        // 假如咱们需要是:5秒钟不进行点击操作,就提醒登录退出        if (nowTime - lastClickTime > 1000 * 5) {          // 提醒一下用户          this.$message({ type: "warning", message: "超时了,已退出登录" });          // 这里要革除定时器,结束任务          clearInterval(this.timer);          // 最初返回到登录页          this.$router.push({ path: "/login" });        }      }, 1000);    },  },  beforeDestroy() {    // 最初一步,来到页面的时候,革除一下定时器,也解绑点击事件    clearInterval(this.timer);    window.removeEventListener("click", () => {}, true);  },};</script>

这里留神一下,层级对应关系,我我的项目搭建的层级关系是Home.vue页面是App.vue页面的外面一层,也有对应的视图,视图对应的也是整个页面的关系。依据层级和路由表路由视图router-view关系,抉择适合的层级去绑定对应的点击事件和定时器即可。

即层级关系是要抉择和login.vue层级平行的下一级才行,否则就会在login.vue页面也会执行定时器和点击绑定事件了

效果图

后端管制(形式二)

思路

这种后端管制形式限制性没有前端管制强,然而也是能够用的。

咱们晓得用户长时间不操作就不会有发申请,这种形式咱们和后端约定如下:

当用户这一次的申请和上一次申请的间隔时间超过肯定工夫,比方超过半小时。那么后端返回的状态码就不是200了,就是一个非凡的状态码,比方是4567这个状态码,那么咱们在前端的响应拦截器中就能够加一个判断,如果状态码是4567就阐明申请超时了,阐明用户长时间未操作,这个时候间接路由跳转到登录页面即可

后端通过JWT机制去管制返回的状态码

代码

这里main.js中的Vue的实例对象咱们将其挂载到全局对象window上,不便咱们在响应拦截器中应用vm对象上的路由跳转办法

main.js文件

// 挂载到window对象上window.vm = new Vue({    store,    router,    render: h => h(App),}).$mount('#app')

响应拦截器文件

http.interceptors.response.use((res) => {    console.log('注册到全局上',vm);    var code = res.data.code;    if(code == 4567){ // 4567是超时状态码,看到这个标识咱们就让用户退出登录        // 留神,这个时候路由跳转就不是this.$router.push()了        vm._router.push({ path: "/login" });    }    return res.data}, (error) => {    // console.log(error)    return Promise.reject(error);})

打印vm实例对象

所以在响应拦截器中路由跳转变成了vm._router.push({ path: "/login" })

总结

上述两种形式的思路都能够应用,具体应用哪种形式,视状况而定