Vuex处理用户Token过期及优化设置封装本地存储操作模块

目录
  • 1. 处理用户 Token
  • 2. 优化封装本地存储操作模块 - 封装localStrage功能
  • 3. Vuex各属性的使用
  • 4. 关于 Token 过期问题
  • 5.优化设置 Token

1. 处理用户 Token

Token 是用户登录成功之后服务端返回的一个身份令牌,在项目中的多个业务中需要使用到:

  • 访问需要授权的 API 接口
  • 校验页面的访问权限
  • ...

问题:Token往哪儿存?

我们只有在第一次用户登录成功之后才能拿到 Token。所以为了能在其它模块中获取到 Token 数据,我们需要把它存储到一个公共的位置,方便随时取用。

本地存储

  • 获取麻烦
  • 数据不是响应式

Vuex 容器(推荐)

  • 获取方便
  • 响应式的

使用容器存储 Token 的思路:

登录成功,将 Token 存储到 Vuex 容器中

  • 获取方便
  • 响应式

为了持久化,还需要把 Token 放到本地存储

  • 持久化

总结: Vuex状态管理工具可有可无 (*・ω-q)

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  // 1. 存储数据的地方 - 类比于vue文件的data()
  state: {
    // 一个对象,储存当前登录用户的token数据
    user: {}
  },
  // 2. 外界修改store中state的属性值,必须通过mutations中设置的修改方法 - 类比methods
  // 注意:这里方法里面的代码和.vue文件中的书写方式有差异,注意区分
  mutations: {
    setUser (state, data) {
      state.user = data
    }
  },
  // 3. 涉及到异步操作后修改state数据时,必须先过actions中的自定义方法,通过actions去调用mutations中的方法
  actions: {
  },
  // 4. 是state中数据的计算属性 - 类比computed
  getters: {
  },
  // 5. 模块化vuex,可以让每一个模块拥有自己的 state、mutation、action、 getters,使得结构非常清晰,方便管理。
  modules: {
  }
})

登录成功以后将后端返回的 token 调用commit方法存到store中

async onSubmit () {
	...
  try {
    const res = await loginAPI(user)
    console.log('登录成功', res)
    // 调用store中的方法,将接口返回的token存到状态管理器中
    this.$store.commit('setUser', res.data.data)
    // 提示 success 或者 fail 的时候,会先把其它的 toast 先清除
    this.$toast.success('登录成功')
  } catch (err) {
    ...
},

3. 将 store中的 token 相关数据存储到容器中

const TOKEN_KEY = 'TOUTIAO_USER'
export default new Vuex.Store({
  state: {
    user: JSON.parse(window.localStorage.getItem(TOKEN_KEY))
  },
  mutations: {
    setUser (state, data) {
      state.user = data
      // 为了防止刷新丢失,需要把数据备份到本地存储
      window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user))
    }
  },
	...
})

2. 优化封装本地存储操作模块 - 封装localStrage功能

创建 src/utils/storage.js 模块

  • 存储
  • 获取
  • 删除
// 封装本地存储操作模块
/* 一个本地存储的数据应该拥有那些特性: 增删改查 */
/*
  储存数据 (新增, 修改)
*/
export const setItem = (key, value) => {
  // 将数组,对象等引用数据类型转化为JSON字符串进行存储
  // 将简单数据类型直接存储
  // 需要外界使用该方法时传入对一个的 键名
  if (typeof value === 'object') {
    // 将数组,对象等引用数据类型转化为JSON字符串进行存储
    value = JSON.stringify(value)
  }
  window.localStorage.setItem(key, value)
}
/*
  获取数据
*/
export const getItem = key => {
  // 如果该键存储的是引用数据类型的JSON字符串,那么需要进行JSON.parse的转化
  const data = window.localStorage.getItem(key)
  // 使用JSON.parse()做JSON数据转化时可能会出现报错
  // 1. 做条件判断(要去找到所有满足、不满足的条件) 2. 做错误判断
  try {
    // 先尝试做JSON.parse()的转化,如果报错了,在把他当成原始数据进行返回
    return JSON.parse(data)
  } catch (error) {
    return data
  }
}
/*
  删除缓存数据
*/
export const removeItem = key => {
  window.localStorage.removeItem(key)
}

在store/index.js引入方法

import { getItem, setItem } from '../utils/storage.js'

使用方法

import { getItem, setItem } from '../utils/storage.js'
const TOKEN_KEY = 'TOUTIAO_USER'
export default new Vuex.Store({
  state: {
    user:getItem(TOKEN_KEY)
  },
  mutations: {
    setUser (state, data) {
      state.user = data
      // 为了防止刷新丢失,需要把数据备份到本地存储
      setItem(TOKEN_KEY, state.user)
    }
  },
	...
})

3. Vuex各属性的使用

创建测试用store.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  // state存放状态,
  state: {
    name: 'tom', // 需要共用的数据
    age: '22'
  },
  // getter为state的计算属性
  getters: {
    getName: (state) => state.name, // 获取name
    getAge: (state) => state.age
  },
  // mutations可更改状态的逻辑,同步操作
  mutations: {
    setName: (state, data) => { state.name = data },
    setAge: (state, data) => { state.age = data }
  },
  // 提交mutation,异步操作
  actions: {
    acSetName (context, name) {
      setTimeout(() => {
        // 延时1秒提交至mutations中的方法
        context.commit('setName', name)
      }, 1000)
    },
    acSetAge (context, age) {
      setTimeout(() => {
        context.commit('setAge', age)
      }, 1000)
    }
  },
  // 将store模块化
  modules: {
  }
})

创建页面comOne.vue测试计算属性

<template>
  <div class="wrapper">
    asd
    <!-- 读取mapGetters中的getName与getAge -->
    <div>
      name:<span>{{ getName }}</span>
    </div>
    <div>
      age:<span>{{ getAge }}</span>
    </div>
  </div>
</template>
<script>
import { mapState, mapGetters } from 'vuex' // 导入vuex的辅助函数
export default {
  components: {},
  // 计算属性computed无法传递参数
  computed: {
    // 映射 state 中的数据为计算属性
    ...mapState(['name', 'age']),
    // 映射 getters 中的数据为计算属性
    ...mapGetters(['getName', 'getAge'])
  }
}
</script>
<style scoped>
</style>

创建comTwo.vue测试同步异步方法

<template>
  <div class="wrapper">
    <div>
      <span>同步修改:</span>
      <!--直接回车调用mapMutations中的setName方法与setAge方法-->
      <input
        v-model="nameInp"
        @keydown.enter="setName(nameInp)"
        placeholder="同步修改name"
      />
      <input
        v-model="ageInp"
        @keydown.enter="setAge(ageInp)"
        placeholder="同步修改age"
      />
    </div>
    <div>
      <span>异步修改:</span>
      <!--直接回车调用mapAtions中的acSetName方法与acSetAge方法-->
      <input
        v-model="acNameInp"
        @keydown.enter="acSetName(acNameInp)"
        placeholder="异步修改name"
      />
      <input
        v-model="AcAgeInp"
        @keydown.enter="acSetAge(AcAgeInp)"
        placeholder="异步修改age"
      />
    </div>
  </div>
</template>
<script>
import { mapMutations, mapActions } from 'vuex' // 导入vuex的辅助函数
export default {
  components: {},
  data () {
    return {
      nameInp: '', // 绑定输入框的值
      ageInp: '',
      acNameInp: '',
      AcAgeInp: ''
    }
  },
  methods: {
    // 用于生成与 mutations 对话的方法,即:包含 $store.commit(xx) 的函数
    ...mapMutations(['setName', 'setAge']),
    // 用于生成与 actions 对话的方法,即:包含 $store.dispatch(xx) 的函数
    ...mapActions(['acSetName', 'acSetAge'])
  }
}
</script>
<style scoped>
</style>

4. 关于 Token 过期问题

登录成功之后后端会返回两个 Token:

  • token:访问令牌,有效期2小时
  • refresh_token:刷新令牌,有效期14天,用于访问令牌过期之后重新获取新的访问令牌

我们的项目接口中设定的 Token 有效期是 2 小时,超过有效期服务端会返回 401 表示 Token 无效或过期了。

为什么过期时间这么短?

  • 为了安全,例如 Token 被别人盗用

过期了怎么办?

  • 让用户重新登录,用户体验太差了
  • 使用 refresh_token 解决 token 过期

如何使用 refresh_token 解决 token 过期?

到课程的后面我们开发的业务功能丰富起来之后,再给大家讲解 Token 过期处理。

大家需要注意的是在学习测试的时候如果收到 401 响应码,请重新登录

5.优化设置 Token

项目中的接口除了登录之外大多数都需要提供 token 才有访问权限。

通过接口文档可以看到,后端接口要求我们将 token 放到请求头 Header 中并以下面的格式发送。

字段名称:Authorization

字段值:Bearer token,注意 Bearertoken 之间有一个空格

方式一:在每次请求的时候手动添加(麻烦)。

axios({
  method: "",
  url: "",
  headers: {
    Authorization: "Bearer token"
  }
})

方式二:使用请求拦截器统一添加(推荐,更方便)。

src/utils/request.js 中添加拦截器统一设置 token:

import axios from 'axios'
import store from '../store/index.js'

const request = axios.create({
  baseURL: 'http://toutiao.itheima.net/' // 接口的基准路径
})

// 请求拦截器
// Add a request interceptor
request.interceptors.request.use(function (config) {
  // Do something before request is sent
  // config :本次请求的配置对象
  // config 里面有一个属性:headers
  const { user } = store.state
  if (user && user.token) {
    config.headers.Authorization = `Bearer ${user.token}`
  }
  return config
}, function (error) {
  // 如果请求出错 - 抛出异常
  // Do something with request error
  return Promise.reject(error)
})

api.user.js注释掉store和获取用户信息携带的请求头

import request from '@/utils/request'
// import store from '@/store'

/**
 * 获取用户自己的信息
 */
export const getUserInfo = () => {
  return request({
    method: 'GET',
    url: '/v1_0/user'
    // 发送请求头数据
    // headers: {
    //   // 注意:该接口需要授权才能访问
    //   //       token的数据格式:Bearer token数据,注意 Bearer 后面有个空格
    //   Authorization: `Bearer ${store.state.user.token}`
    // }
  })
}

以上就是Vuex处理用户Token优化设置封装本地存储操作模块的详细内容,更多关于Vuex处理用户Token的资料请关注我们其它相关文章!

(0)

相关推荐

  • 关于Vue 消除Token过期时刷新页面的重复提示问题

    token过期时,刷新页面,页面如果加载时向后端发起多个请求,会重复告警提示,经过处理,只提示一次告警. 1.问题现象   页面长时间未操作,再刷新页面时,第一次弹出"token失效,请重新登录!"提示,然后跳转到登录页面,接下来又弹出了n个"Token已过期"的后端返回消息提示. 2.原因分析   当前页面初始化,有多个向后端查询系统参数的调用,代码如下: created () { // ======================================

  • Vue中如何处理token过期问题

    目录 解决方案 方案一 方案二 方案三:封装axios基本结构 1.token是存在localStorage中 2.问题和优化 3.完整版 后端为了安全,token一般存在有效时间,当token过期,所有请求失效 解决方案 方案一 在请求发起前拦截每个请求,判断token的有效时间是否已经过期,若已过期,则将请求挂起,先刷新token后再继续请求. 优点: 在请求前拦截,能节省请求,省流量 缺点: 需要后端额外提供一个token过期时间的字段:使用了本地时间判断,若本地时间被篡改,特别是本地时间

  • Vue利用路由钩子token过期后跳转到登录页的实例

    在Vue2.0中的路由钩子主要是用来拦截导航,让它完成跳转或前取消,可以理解为路由守卫. 分为全局导航钩子,单个路由独享的钩子,组件内钩子. 三种 类型的钩子只是用的地方不一样,都接受一个函数作为参数,函数传入三个参数,分别为to,from,next. 其中next有三个方法 (1)next(); //默认路由 (2)next(false); //阻止路由跳转 (3)next({path:'/'}); //阻止默认路由,跳转到指定路径 这里我使用了组件内钩子进行判断token过期后跳转到登录页,

  • vue实现token过期自动跳转到登录页面

    这几天项目提测,测试给我提了个bug,说token过期,路由应该自动跳转到登陆页面,让用户重新登录.先说下一些前置条件, 1:我公司的token时效在生产环境设置为一个小时,当token过期,所有接口都直接返回 2:每次路由跳转都会对token进行判断,设置了一个全局的beforeEach钩子函数,如果token存在就跳到你所需要的页面,否则 就直接跳转到登录页面,让用户登录重新存取token 接口返回的信息 { code:10009, msg:'token过期', data:null } 全局

  • Vue 拦截器对token过期处理方法

    最近在做的一个项目,需要每个http请求下 都要添加token,这样无疑是增加了工作量.而vue 拦截器interceptors正好可以解决我们的需求. Vue.http.interceptors.push(function (request, next) {//拦截器设置请求token // sessionStorage.getItem("tokenUrl"); request.headers.set('token', sessionStorage.getItem("tok

  • Vuex处理用户Token过期及优化设置封装本地存储操作模块

    目录 1. 处理用户 Token 2. 优化封装本地存储操作模块 - 封装localStrage功能 3. Vuex各属性的使用 4. 关于 Token 过期问题 5.优化设置 Token 1. 处理用户 Token Token 是用户登录成功之后服务端返回的一个身份令牌,在项目中的多个业务中需要使用到: 访问需要授权的 API 接口 校验页面的访问权限 ... 问题:Token往哪儿存? 我们只有在第一次用户登录成功之后才能拿到 Token.所以为了能在其它模块中获取到 Token 数据,我们

  • JWT 设置token过期时间无效的解决

    目录 JWT 设置token过期时间无效 原因 原因分析 JWT token过期自动续期解决方案 JWT token token过期刷新方案 JWT 设置token过期时间无效 原因 设置超时时间的顺序有误, 应调用setClaims()方法设置claims属性. 在调用setExpiration()方法设置超时时间. Date expiresDate = new Date(System.currentTimeMillis() + expire_time);// expire_time为toke

  • Android token过期刷新处理的方法示例

    token token的意思是"令牌",是用户身份的验证方式,最简单的token组成:uid(用户唯一的身份标识).time(当前时间的时间戳).sign(签名,由token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接token请求服务器).还可以把不变的参数也放进token,避免多次查库. 第一种方案 通过okhttp提供的Authenticator接口,但是只有HTTP返回码为401时才会触发.此种方式局限性很大,要求后台设计必须符合规范.在实际项目中

  • vue-router结合vuex实现用户权限控制功能

    为了实现前端校验用户,后端需要在用户登录的时候记录下该用户的状态并加密之后返回给前端.之后该用户的所有请求都应该附带这个加密后的状态,后端取到这个状态解密,并与之前保存的状态对比,以此来判断该用户是否登录或合法. 我这里使用了node简单了写了个本地的express服务,来实现上述功能.完整的代码直接贴出来: // server.js const express = require('express'); const bodyParser = require('body-parser'); co

  • 请求时token过期自动刷新token操作

    1.在开发过程中,我们都会接触到token,token的作用是什么呢?主要的作用就是为了安全,用户登陆时,服务器会随机生成一个有时效性的token,用户的每一次请求都需要携带上token,证明其请求的合法性,服务器会验证token,只有通过验证才会返回请求结果. 2.当token失效时,现在的网站一般会做两种处理,一种是跳转到登陆页面让用户重新登陆获取新的token,另外一种就是当检测到请求失效时,网站自动去请求新的token,第二种方式在app保持登陆状态上面用得比较多. 3.下面进入主题,我

  • 微信小程序如何处理token过期问题

    目录 先说结论 问题 解决方案 使用Promise封装回调函数 总结 先说结论 业务流程:  从网络日志中检查到token过期,则跳转到登录页面,要求用户重新登录. 代码逻辑:使用自定义的HttpUtil封装wx.request API,全局捕获过期token并自动处理后,下发给上层业务. 问题 Token过期的现象: 在网络请求中,客户端token会过段时间过期,使得后续的网络请求失败,抛出异常日志如下: data: {code: "99997", date: 16341748313

  • Oracle用户密码过期和用户被锁的解决方法

    今天正在上班的过程中,客户反映了他们的系统登录不了,经过我的一番检查,发现是因为数据库密码过期导致的,在网上查找相关资料发现还真有此种情况发生,在此顺便做了个整理,以便共同交流! 产生原因: 在oracle11g中默认在default概要文件中设置了"PASSWORD_LIFE_TIME=180天"所导致. 在oracle11g中默认在default概要文件中设置了"FAILED_LOGIN_ATTEMPTS=10次",当输入密码错误次数达到设置值将导致此问题. 解

  • MySQL MyISAM 优化设置点滴

    最近在配置mysql服务器需要用到的一些设置,经过测试发现比较不错的配置方案,亮点在最后啊 先说一点问题:   Mysql中的InnoDB和MyISAM是在使用MySQL中最常用的两个表类型,各有优缺点.两种类型最主要的差别就是 InnoDB 支持事务处理与外键和行级锁.而MyISAM不支持.所以Myisam往往就容易被人认为只适合在小项目中使用.但是从数据库需求角度讲,要求99.9%的稳定性,方便的扩展性和高可用性来说的话,那MyISAM绝对应该是首选.MyISAM类型的表强调的是性能,其执行

随机推荐