Token 的失效处理和无感刷新的两种方法

本文介绍了两种处理Token失效的方法,一种是基于Vue.js的路由前置守卫,当时间戳超时时使用refresh-token更新token;另一种是在React.js中,通过refresh_token获取新token。讨论了Token的有效时间、为何需要refresh_token以及常见的处理流程,旨在提升用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 通过 timeStamp, 超过时间,就用 refresh-token去更换 新的 token — 基于 vue 实现

在路由前置守卫处理

定义路由前置守卫

router.beforeEach((to, from, next) => {
    next()
})

登录成功存时间戳

import { setItem } from '@/utils/storage.js'
setItem('TOKENDATE', Date.now())

进入路由之前进行判断token

import { getItem } from '@/utils/storage.js'

// 约定的过期时间
const tokenTimeOut = 5 * 60 * 1000

router.beforeEach((to, from, next) => {
  console.log('判断token有没有过期')
  // 获取登陆的时间戳
  const loginDate = getItem('TOKENDATE')
  // 获取进入页面的当前时间戳
  const currentDate = Date.now()

  console.log((currentDate - loginDate) > tokenTimeOut)
  // next()
})

封装请求方法

/**
 * 获取token
 * @returns promise
 */
export const getToken = () => {
  return request({
    method: 'PUT',
    url: '/v1_0/authorizations'
  })
}

调用方法

router.beforeEach(async (to, from, next) => {
    console.log('判断token有没有过期')
    // 获取登陆的时间戳
    const loginDate = getItem('TOKENDATE')
    // 获取进入页面的当前时间戳
    const currentDate = Date.now()
    if ((currentDate - loginDate) > tokenTimeOut) {
        // 刷新token
        const res = await getToken()
        store.commit('initUser', {
            ...store.state.user,
            token: res.data.data.token
        })
    }
    next()
})

请求拦截器判断携带refresh_token

request.interceptors.request.use(config => {
  // config: 每次请求的配置和请求的基本信息
  Toast.loading({
    message: '加载中...',
    forbidClick: true,
    duration: 0
  })
  const { user } = store.state
  // 判断用户登录 并且访问获取toekn接口
  if (user && user.token && config.url === '/v1_0/authorizations' && config.method === 'put') {
    config.headers.Authorization = 'Bearer ' + user.refresh_token
  } else if (user && user.token) {
    config.headers.Authorization = 'Bearer ' + user.token
  }
  return config
})

在vue中 重置时间戳

mutations: {
    // 初始化user数据
    initUser (state, data) {
      // 同步vuex数据
      state.user = data
      // 本地存贮 setItem('HMTT_TOKEN', data)
      setItem('HMTT_TOKEN', data)
      // 存时间戳
      setItem('TOKENDATE', Date.now())
    }
  }

2. token 过期或者失效,再通过 refresh_token 去获取新的 token ,基于 reacjs

Token: 访问令牌,通过这个token就能够访问到需要权限的页面

  • Token 有效时间都不会太长,一般就是 1-2个小时
  • Token 过期的处理

​ * 重新登录(适合PC端的管理系统)

​ * 对于移动端资讯类的项目,用户体验不好

Refresh_token: 刷新令牌,没有访问的功能,通过刷新令牌能够获取到一个新的访问令牌,它的有效时间比较长

  • 为什么需要刷新令牌?

    – 1. 在项目中,客户端多次请求有权限的数据,都会携带 token.如果被抓包,用户的 token 就会暴露。

    – 2. 如果黑客能够抓到 Refresh_token, 他也不太容易搞清楚,服务端是规定如何刷新 token 的,因为 https 协议都是**密文(http+SSL/TSL)**传输的

常用的处理流程:
在这里插入图片描述

2.1 code

request.js

import { Toast } from "antd-mobile";
import axios from "axios";
import localStorage from "local-storage";
import { TOKEN } from "@/store/constants";
import history from "./history";
import store from "@/store";
import { logOut, saveToken } from "@/store/action/login";

// 1. 创建新的 axios 实例
const baseURL = "http://geek.itheima.net/v1_0/";
const request = axios.create({
  baseURL,
  timeout: 5000,
});

// 2. 设置请求拦截器和响应拦截器
request.interceptors.request.use((config) => {
  const token = localStorage.get(TOKEN)?.token;

  if (token) {
    config.headers["Authorization"] = "Bearer " + token;
  }
  return config;
});

request.interceptors.response.use(
  (response) => {
    return response.data;
  },
  async (error) => {
    // 1. 网络异常
    if (!error.response) {
      Toast.fail("服务器繁忙,请稍后重试!", 1);
      return Promise.reject(error); // return 响应错误,调用的函数不应该往下执行
    }
    const { response, config } = error;
    // 2.服务器异常
    if (error.response?.status !== 401) {
      Toast.info(response.data.message);
      return Promise.reject(error);
    }

    // 3. refresh_token 是不是被删除了?
    const { refresh_token } = localStorage.get(TOKEN);
    console.log("refresh", refresh_token);
    if (!refresh_token) {
      history.push("/login", { state: { from: history.location } });
      return Promise.reject(error);
    }

    //4. 有 refreshToken,就拿着 refresh_token 去无感刷新
    try {
      const res = await axios({
        method: "put",
        url: baseURL + "authorizations", // 字符串拼接,不能多/;如果 baseURL, 通过 request, axios 会去处理
        headers: {
          Authorization: "Bearer " + refresh_token,
        },
      });

      const newToken = {
        token: res.data.data.token,
        refresh_token,
      };

      // 设置完新的 token,请求后,要 return; 如果 没有设置成新的token,一起请求,会造成一直 401
      store.dispatch(saveToken(newToken));
      localStorage.set(TOKEN, newToken);

      return request(config);
    } catch (error) {
      // refresh_token 过期了
      store.dispatch(logOut());
      history.push("/login", { from: history.location });
      Toast.info("用户信息失效,请重新登录!", 1);
      return Promise.reject(error); // 返回,是action中的dispatch的await不会一直等待
    }
  }
);

// 3. 导出该 axios 实例
export default request;

history.js

import { createBrowserHistory } from "history";

export default createBrowserHistory();

App.js

import AuthRoute from "@/components/AuthRoute/AuthRoute";
import React, { lazy, Suspense } from "react";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import history from "@/utils/history";

const Layout = lazy(() => import("./pages/Layout"));
const Login = lazy(() => import("./pages/Login"));
const EditProfile = lazy(() => import("./pages/Profile/EditProfile"));
const EditChat = lazy(() =>
  import("./pages/Profile/EditProfile/components/EditChat")
);

function App() {
  return (
    <Router history={history}>
      <div className="App">
        <Suspense fallback={<div>...loading</div>}>
          <Switch>
            <Redirect exact from="/" to="/home" />
            <Route path="/home" component={Layout} />
            <Route path="/login" component={Login} />

            <AuthRoute path="/profile/edit" component={EditProfile} />
            <AuthRoute path="/profile/chat" component={EditChat} />
          </Switch>
        </Suspense>
      </div>
    </Router>
  );
}

export default App;

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值