IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Token 的失效处理和无感刷新的两种方法 -> 正文阅读

[JavaScript知识库]Token 的失效处理和无感刷新的两种方法

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;

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:14:30  更:2021-09-14 13:14:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 12:22:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计