vue3项目学习三:配置登陆解决方案

配置登陆解决方案

  • 配置环境变量
  • 封装axios
    • 封装接口请求模块
    • 封装登录请求
    • 触发登录动作
    • 本地缓存处理方案
      • LocalStorage
    • 登录鉴权
    • 退出登录方案
      • 主动退出
      • 被动退出

配置环境变量

在根目录创建开发模式和生产模式的两种baseURL
vue3项目学习三:配置登陆解决方案_第1张图片
输入:

ENV='development'

# base api
VUE_APP_BASE_API='/api'

修改vue.config.js代理

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://xxxxx/',
        changeOrigin: true
      }
    }
  }
}

封装axios

安装axios

npm i axios --save

创建封装文件:src -> utils -> request.js

import axios from 'axios'
import { ElMessage } from 'element-plus'
import store from '@/store'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    // 注入token
    if (store.state.user.token) {
      // 如果存在token则注入token
      config.headers.Authorization = `Bearer ${store.state.user.token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  // 请求成功
  response => {
    // 根据接口返回情况设置,此处为接口返回包括 success ,message , data
    const { success, message, data } = response.data
    // 判断当前请求是否成功? 返回解析后的数据 : 失败后消息提示
    if (success) {
      return data
    } else {
      // 失败,返回消息提示,使用element消息message模块
      ElMessage.error(message)
      return Promise.reject(new Error(message))
    }
  },
  // 请求失败 404 500 等
  error => {
    ElMessage.error(error.message)
    return Promise.reject(error)
  }
)

export default service


封装接口请求模块

创建api文件夹 -> sys.js
实例

import request from '@/utils/request'
/**
 * 登陆
 */
export const login = data => {
  return request({
    url: '/sys/login',
    method: 'POST',
    data
  })
}

封装登录请求

登录动作封装在vuexaction中,在store下创建modules文件夹,创建user.js模块,用于处理所有与用户相关的内容。
vue3项目学习三:配置登陆解决方案_第2张图片

store -> modules -> user.js

import { login } from '@/api/sys'

export default {
  namespaced: true,
  state: () => ({

  }),
  mutations: {

  },
  actions: {
    /**
     * 登录请求动作
     */
    login (context, userInfo) {
      const { username, password } = userInfo
      return new Promise((resolve, reject) => {
        login({ username, password }).then(data => {
          resolve(data)
        }).catch(err => {
          reject(err)
        })
      })
    }
  }
}

store -> index.js

import { createStore } from 'vuex'
import user from './modules/user'

export default createStore({
  modules: {
    user
  }
})

触发登录动作

login.vue

import { useStore } from 'vuex'

const store = useStore()
const handlelogin = () => {
	// 1.表单验证
	store.dispatch('user/login' , loginForm.value).then(()=>{
	// 2.登录后处理
	})
}

本地缓存处理方案

通常获取到token之后使用localStorageVuex
保存在 Localstorage 是为了方便实现 自动登录功能
保存在 vuex 中是为了后面在其他位置进行使用

LocalStorage

utils -> storage.js

/**
 * 存储数据
 */
export const setItem = (key, value) => {
  // value 分为两种情况:
  // 1.基数据类型
  // 2.复杂数据类型
  if (typeof value === 'object') {
    value = JSON.stringify(value)
  }
  window.localStorage.setItem(key, value)
}
/**
 * 获取数据
 */
export const getItem = key => {
  const data = window.localStorage.getItem(key)
  try {
    return JSON.parse(data)
  } catch (err) {
    return data
  }
}
/**
 * 存储数据
 */
export const removeItem = key => {
  window.localStorage.removeItem(key)
}
/**
 * 存储数据
 */
export const removeAllItem = () => {
  window.localStorage.clear()
}

使用案例:store-> modules -> user.js

import { login } from '@/api/sys'
import { setItem, getItem } from '@/utils/storage'

export default {
  namespaced: true,
  state: () => ({
    token: getItem('token') || ''
  }),
  mutations: {
    setToken (state, token) {
      state.token = token
      setItem('token', token)
    }
  },
  actions: {
    /**
     * 登录请求动作
     */
    login (context, userInfo) {
      const { username, password } = userInfo
      return new Promise((resolve, reject) => {
        login({ username, password }).then(data => {
          this.commit('user/setToken', data.token)
          resolve(data)
        }).catch(err => {
          reject(err)
        })
      })
    }
  }
}

登录鉴权

当用户未登陆时,不允许进入除 login 之外的其他页面
用户登陆后,token 未过期之前,不允许进入 login 页面

而想要实现这个功能,那么最好的方式就是通过 路由守卫 来进行实现
main.js平级创建permission.js文件

vue3项目学习三:配置登陆解决方案_第3张图片
在main.js导入
vue3项目学习三:配置登陆解决方案_第4张图片
permission.js

import router from '@/router'
import store from '@/store'

// 白名单,可以包括404,500等页面
const whiteList = ['/login']

/**
 * 路由前置守卫
 */
router.beforeEach((to, from, next) => {
  if (store.state.user.token) {
    // 1.用户已登录,不允许进入login
    if (to.path === '/login') {
      next('/')
    } else {
      next()
    }
  } else {
    // 2.用户未登录,只允许进入login
    if (whiteList.indexOf(to.path) > -1) {
      // 在白名单,直接通过
      next()
    } else {
      next('/login')
    }
  }
})

退出登录方案

  1. 主动退出指: 用户点击登录按钮之后退出
  2. 被动退出指: token 过期或被 其他人”顶下来“时退出

那么无论是什么退出方式,在用户退出时,所需要执行的操作都是固定的:

  1. 清理掉当前用户缓存数据
  2. 清理掉权限相关配置
  3. 返回到登录页

主动退出

store/modules/user.js 中,添加对应action

logout () {
  this.commit('user/setToken', '')
  this.commit('user/setUserInfo', {})
  removeAllItem()
  // TODO: 清理权限相关
  router.push('/')
}

退出时调用该方法即可

被动退出

用户被动退出的场景主要有两个:

  1. token 失效
  2. 单点登录:其他人登录该账号被“顶下来"

那么这两种场景下,在前端对应的处理方案一共也分为两种,共分为 主动处理、被动处理 两种:

  1. 主动处理:主要应对 token 失效
  2. 被动处理:同时应对 token 失效与单点登录

1.主动处理
此时用到的是“时效token”,对于 token 本身是拥有时效的,但是通常情况下这个时效都是在服务端进行处理。而此时我们要在服务端处理token时效的同时在前端主动介入token’时效的处理中。 从而保证用户信息的更加安全性。

对应到代码中的实现方案为

  1. 在用户登陆时,记录当前 登录时间
  2. 制定一个 失效时长
  3. 在接口调用时,根据 当前时间 对比 登录时间,看是否超过了 时效时长
    1. 如果未超过,则正常进行后续操作
    2. 如果超过,则进行 退出登录 操作

创建 utils/auth.js 文件,并写入以下代码

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

const TIME_STAMP = 'timeStamp'
const TOKEN_TIMEOUT_VALUE = 2 * 3600 * 1000

/**
* 获取时间戳
*/
export function getTimeStamp () {
  return getItem(TIME_STAMP)
}
/**
*设置时间戳
*/
export function setTimeStamp () {
  setItem(TIME_STAMP, Date.now())
}
/**
*是否超时
*/
export function isCheckTimeout () {
  // 当前时间
  const currentTime = Date.now()
  // 缓存时间
  const timeStamp = getTimeStamp()
  return currentTime - timeStamp > TOKEN_TIMEOUT_VALUE
}

登录成功后设置时间戳,保存登录时间 -> 跳转页面 ,在每次请求接口时检查时间是否超时:
vue3项目学习三:配置登陆解决方案_第5张图片
2. 被动处理
utils/request的响应拦截器中增加一下逻辑:

// 响应拦截器
service.interceptors.response.use(
  // 请求成功
  response => {
    // 根据接口返回情况设置,此处为接口返回包括 success ,message , data
    const { success, message, data } = response.data
    // 判断当前请求是否成功? 返回解析后的数据 : 失败后消息提示
    if (success) {
      return data
    } else {
      // 失败,返回消息提示,使用element消息message模块
      ElMessage.error(message)
      return Promise.reject(new Error(message))
    }
  },
  // 请求失败 404 500 等
  error => {
    if (error.response && error.response.data && error.response.data.code === 401) {
      store.dispatch('user/logout')
    }
    ElMessage.error(error.message)
    return Promise.reject(error)
  }
)

你可能感兴趣的:(vue3学习,学习,vue)