前端判断Token是否失效,并更新Token

news/2024/12/13 4:50:35/

用户登录系统后,都会赋予用户一个Token,这样用户在操作系统时,只需要将Token传给后端就可以了,无需对用户重复进行身份验证

既然Token如此重要,为了安全起见,Token的有效期也不会设置过长。

那么将由前后端谁来判断Token是否失效呢?只能说各有优劣

前后端优缺点

// 简单说一下主要几点
// 前端
优点:体验好,减少服务端的负担;
缺点:不安全,依赖本地时间,可以被伪造或篡改,容易被攻击者利用;
// 后端
优点:安全性高,只有服务端知道Token是否失效,可以防止客户端伪造或篡改信息;还能简化前端处理逻辑;
缺点:增加了服务端的负担,每次请求都需要进行验证,可能对性能有影响

前端处理逻辑

本期主要重点讲 前端是如何处理Token失效逻辑的。

为了不频繁更新Token,前端应该设置一个更新时间失效时间

分析

场景和逻辑很简单:

  • 1、用户登录系统,后端返回前端Token有效期时间(3天);
    那么更新时间设为2天半后失效时间设为3天后

  • 2、用户在3天后访问系统判断其Token失效,去往登录页重新登录

  • 3、用户在2天半前访问系统,则不需要特殊处理,使用本地储存的Token就可以了;
    更新时间不变,但是失效时间应该改为 当前时间 + 3天

  • 4、用户在2天半 — 3天这个时间段访问系统,则需要请求后端返回Token
    更新时间和失效时间 则需要执行步骤1的逻辑

代码逻辑

主要有两处地方需要添加逻辑:
1、项目中 pinia/vuex 状态管理库,需要对时间进行储存和判断
2、接口请求时,公共api层是否需要更新token

pinia状态管理

// 不同项目,不同开发习惯,目录结构都不一样; 这里主要凸显出这是一个状态管理库文件
// store/modules/global.js 
// 使用pinia储存: 更新时间、失效时间、Tokenimport { defineStore } from 'pinia'export const glStore = defineStore('glStore', {persist: {storage: {setItem(key, value) {uni.setStorageSync(key, value)},getItem(key) {return uni.getStorageSync(key)}}},state: () => {return {token: '',userInfo: {},// 失效时间expirationTime: 0,// 更新时间updateTime: 0}},actions: {setToken(value) {this.token = value},setUserInfo(userInfo) {if (userInfo.token) {this.setToken(userInfo.token)delete userInfo.token}this.userInfo = userInfo},getDate() {// 3天const threshold = 3 * 24 * 60 * 60 * 1000// 失效前半天const interval = 12 * 60 * 60 * 1000const now = new Date()// 当前时间const currentTime = now.getTime()// 失效时间const failure = currentTime + threshold// 更新时间const update = threshold + currentTime - intervalconsole.log(update, this.formatTime(update), '--------2天半后')console.log(failure, this.formatTime(failure), '--------3天后')console.log(currentTime, this.formatTime(currentTime), '--------当前时间')// 1:更新Token// 2:更新失效期;// 3:Token失效了;// 4:未知if (!this.expirationTime) {this.expirationTime = failurethis.updateTime = updatereturn '1'} else {// 当前时间 小于 更新时间if (currentTime < this.updateTime) {// 更新失效时间为  最新当前时间的3天后this.expirationTime = failurereturn '2'} else if (currentTime > this.updateTime && currentTime > this.expirationTime) {// 更新Token--- 重复最开始操作this.expirationTime = failurethis.updateTime = updatereturn '1'} else if (currentTime > this.updateTime) {// 当前时间 大于  失效时间 == Token失效return '3'} else {return '4'}}},formatTime(timestamp) {const date = new Date(timestamp)const formattedDate = date.toLocaleString()return formattedDate}}
})

API 请求

// 接口域名
import { host } from '$api/baseUrl.js'
// 设置请求头
import { setHeader } from './sign'
// pinia
import { glStore } from '@/store/modules/global.js'
// 请求后拦截
function responseFn(res, resolve, reject) {if (res.code === 0) {resolve(res)} else if (res.code === 401300) {// token过期uni.showModal({// 弹出提示框title: '重新登录',content: '登录过期,请重新登录!',success(res) {if (res.confirm) {// 用户点击确定按钮uni.navigateTo({ url: '/pages/login/index' })}},fail(e) {console.log(e, '确认取消弹出未弹出')}})} else {uni.showToast({title: res.msg,icon: 'none',duration: 1000})reject(res)}
}async function fetch(url, data = {}, method = 'POST') {const store = glStore()let type = store.getDate()// 不需要Token的接口let urls = ['xxx/code', 'xxx/login']if (type === '1' && !urls.includes(url)) {let res = await $ajax('url---token', data, method)store.setUserInfo(res.data)}return $ajax(url, data, method)
}async function $ajax(url, data = {}, method = 'POST') {return new Promise((resolve, reject) => {uni.request({url: host + url,header: setHeader({url,method,data: data || {}}),data,method,success(res) {responseFn(res.data, resolve, reject)},fail: function(err) {uni.hideLoading()reject(err)}})})
}const $get = (url = '', data = {}) => {return fetch(url,data,'get')
}const $post = (url = '', data = {}) => {return fetch(url,data)
}const $delete = (url = '', data = {}) => {return fetch(url,data,'delete')
}const $put = (url = '', data = {}) => {return fetch(url,data,'put')
}export { $get, $post, $delete, $put }

http://www.ppmy.cn/news/1554669.html

相关文章

Redis与数据库数据一致性保障方法

保证Redis和数据库数据一致性是一个复杂但至关重要的问题&#xff0c;特别是在需要高速缓存和持久化存储并存的系统中。以下是一些常用的方法来确保Redis和数据库之间的数据一致性&#xff1a; 一、事务与回滚机制 Redis事务&#xff1a;Redis支持通过MULTI、EXEC、DISCARD和…

微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…

PostgreSQL/PostGIS中提升空间查询(分析)性能(效率)的一些方法

目录 1. 使用适当的索引 1.1 索引类型 1.2 分析查询计划 1.3 覆盖索引 1.4 复合索引 1.5 维护索引 1.6 删除不必要的索引 1.7 使用适当的数据类型 2. 建立分区表 2.1 分区表的基本概念 2.2 创建分区表的步骤 2.3 空间数据的分区 2.4 分区表优点 3. 简化几何形状 …

Java春招大厂面试题

文章目录 软件开发2024春招大厂面试题1. redis的跳表是怎么实现的&#xff1f;2. MVCC实现原理3. Redis怎么实现延时消息4. http默认端口号是多少5. http的几种请求&#xff08;get、post…&#xff09;有什么区别1. GET2. POST 6. Http和Https的区别7. tcp协议中&#xff0c;三…

python3D圣诞树

import pygame import math from pygame.locals import *# 初始化Pygame pygame.init()# 设置屏幕尺寸和标题 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption(3D 圣诞树)# 设置颜色 GREEN (34, 139, 34) BROWN (139,…

数据分析案例-笔记本电脑价格数据可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

单片机读写内部flash实现断电数据存储

在单片机编程中&#xff0c;读写内部Flash存储器是一种常见的方法来实现断电数据存储。这里以STM32系列单片机为例&#xff0c;展示如何通过HAL库进行简单的内部Flash读写操作。 以下是一个完整的示例代码&#xff0c;展示了如何擦除、写入和读取内部Flash中的数据。请注意&am…

windows下 mysql开启 binlog日志

一、查看是否开启 binlog -- 方式一 show binary logs;-- 方式二 show VARIABLES like log_bin 说明没有开启 方式一 &#xff1a;you are not using binary logging 方式二&#xff1a;log_bin off 二、编辑 my.ini 配置文件 默认安装地点位于&#xff1a;C:\ProgramDat…