Vue后台开发实例教程(八)防止token过期,动态刷新token
小白浏览:7042024-03-26 08:56:47本文累计收益:0我也要赚钱

本实例教程是.net core 系列实例开发教程-权限管理系统前端开发教程,使用PanJiaChen写的Vue后台模板。

本文源码下载地址:http://www.80cxy.com/Blog/ResourceView?arId=202403191532545995NAAqJh

系列教程地址:http://www.80cxy.com/Blog/ArticleView?arId=202403191517574161ay3s5V

服务端生成的token是有过期时间限制的,如30分钟之内有效,超过30分钟就过期了,这时前台需要重新登录,如果用户一直使用着系统,这样用户体验很不好,本文处理方法是前端提交token快过期时,服务端返回一个刷新token的标识,前端收到标识就请求重新获取token。

一、后台代码

后台代码主要判断token是否快过期,如果快过期,返回一个更新token标识。

            //获取token过期时间
            DateTime expDate = context.HttpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Exp)
                .Select(x => x.Value).FirstOrDefault().GetTimeSpmpToDate();
            //判断jwt是否过期
            if ((expDate - DateTime.Now).TotalMinutes < 0)
            {
                context.Result = new JsonResult(new ResponseContent().Error(ResponseType.TokenExpiration));
                return;
            }
            //前端刷新token标识,离过期5分钟时开始刷新
            if ((expDate - DateTime.Now).TotalMinutes < 5 && context.HttpContext.Request.Path != replaceTokenPath)
            {
                context.HttpContext.Response.Headers.Add("vol_exp", "1");
            }

二、前端改造代码

修改src/utils/request.js请求代码:

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

/*********axios二次封装,对外暴露service实例**********/
//创建一个 axios 实例,service就是axios
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

//请求拦截器,请求发出去之前做一些事情
service.interceptors.request.use(
  config => {
    //config配置对象,包含请求头headers
    //判断程序内是否保存token,
    if (store.getters.token) {
      // let each request carry token
      //设置请求携带token,服务器端命名为Authorization
      config.headers['Authorization'] = 'Bearer ' + getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

//响应拦截器
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  //成功的回调
  response => {

    //token刷新标识
    let vol_exp = "";
    if (response.headers.vol_exp != undefined) {
      vol_exp = response.headers.vol_exp;
    }

    //接收返回数据
    const res = response.data
    // 响应失败,处理
    if (res.code !== 200) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 401: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 401) {
        // to re-login
        MessageBox.confirm('您已注销,您可以取消以留在此页面上,或重新登录', '确认退出', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {

      //服务端返回token刷新标识
      if (vol_exp == "1") {
        //刷新token
        replaceToken();
      }

      //响应成功
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)
//以下是动态刷新token新增代码
//动态刷新token
function replaceToken() {
  ajax({
    url: "/api/AdminLogin/RefreshToken",
    param: {},
    json: true,
    success: function (res) {
      if (res.code == 200) {
        store.dispatch('user/RefreshToken', res.data.token).then(() => {
          console.log("token刷新成功")
        })
      } else {
        console.log("Error");
        location.reload()
      }
    },
    errror: function (ex) {
      console.log("Error");
      location.reload()
    },
    type: "post",
    async: false
  });
}

function createXHR() {
  if (XMLHttpRequest) {
    return new XMLHttpRequest();
  }
  if (ActiveXObject) {
    if (typeof arguments.callee.activeXString != "string") {
      var versions = [
        "MSXML2.XMLHttp.6.0",
        "MSXML2.XMLHttp",
        "MSXML2.XMLHttp.3.0"
      ];
      for (var i = 0; i < versions.length; i++) {
        try {
          new ActiveXObject(versions[i]);
          arguments.callee.activeXString = versions[i];
          break;
        } catch (e) {
          console.log(e);
        }
      }
    }
    return new ActiveXObject(arguments.callee.activeXString);
  }
}

function ajax(param) {
  let httpParam =
    Object.assign({
      url: '', headers: {},
      param: {}, json: true,
      success: function () { },
      errror: function () { },
      type: 'post', async: true
    }, param);

  httpParam.url = process.env.VUE_APP_BASE_API + "/" + httpParam.url.replace(/\/?/, '');
  httpParam.headers['Authorization'] = 'Bearer ' + getToken()
  var xhr = createXHR();
  xhr.onreadystatechange = function () {
    if (xhr.status == 403 || xhr.status == 401) {
      redirect(xhr.responseText);
      return;
    }
    //checkResponse(xhr);
    if (xhr.readyState == 4 && xhr.status == 200) {
      httpParam.success(httpParam.json ? JSON.parse(xhr.responseText) : xhr.responseText);
      return;
    }
    if (xhr.status != 0 && xhr.readyState != 1) {
      httpParam.errror(xhr);
    }
  };
  //初始化请求
  xhr.open(
    httpParam.type,
    httpParam.url,
    httpParam.async
  );
  xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  for (const key in httpParam.headers) {
    xhr.setRequestHeader(key, httpParam.headers[key]);
  }
  let dataStr = '';
  for (const key in httpParam.param) {
    dataStr += key + "=" + httpParam.param[key];
  }
  try {
    xhr.send(dataStr);
  } catch (error) {
    toLogin();
  }
}

ajax.post = function (url, param, success, errror) {
  ajax({ url: url, param: param, success: success, error: errror, type: 'post' })
}
ajax.get = function (url, param, success, errror) {
  ajax({ url: url, param: param, success: success, error: errror, type: 'get' })
}

function toLogin() {
  this.$router.push({ path: '/login', params: { r: Math.random() } });
}
export default service

 

评论列表
发表评论
+ 关注