vue3 + Element-plus 开发后台管理系统(12)

354 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

搭建登录架构解决方案与实现

这一篇,我们来看一看本地缓存及登录鉴权的相关内容

本地缓存处理方案

通常状态下,我们获取到 token 后,会将其进行缓存,而缓存的方案实际上有两种:

1、本地缓存:LocalStorage

2、全局状态管理:Vuex

保存在 LocalStorage 中是为了实现自动登录

而保存在 vuex 中则是为了其他地方的使用

下边来看一看两种缓存方案的实现:

LocalStorage

1、创建 utils/storage.js 文件,封装三个对应的方法

/**
 * 存储数据
 */
export const setItem = (key, value) => {
  // 将数组、对象类型的数据转化为 JSON 字符串进行存储
  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 = key => {
  window.localStorage.clear()
}

Vuex

为了方便获取 token 的常量名,我们需要创建 constant 目录,创建 constant/index.js,这个文件将来也可用来保存其他的常量

export const TOKEN = 'token'

vuexuser 模块下对 token 进行处理

import { login } from '@/api/sys'
import md5 from 'md5'
import { setItem, getItem } from '@/utils/storage'
import { TOKEN } from '@/constant'
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: md5(password)
        })
          .then(data => {
            this.commit('user/setToken', data.data.data.token)
            resolve()
          })
          .catch(err => {
            reject(err)
          })
      })
    }
  }
}

至此,我们登录的时候就可以将 token 存储在 vuex 以及 localStorage

响应数据统一处理

上边我们保存 token 时是通过 data.data.data.token 进行获取的,但这这种写法着实让人感觉难受,所以我们通过 axios 的响应拦截器对其进行一下处理

utils/request.js 中增加如下内容

import axios from 'axios'
import { ElMessage } from 'element-plus'

// 响应拦截器
service.interceptors.response.use(
  response => {
    const { success, message, data } = response.data
    //   要根据success的成功与否决定下面的操作
    if (success) {
      return data
    } else {
      // 业务错误
      ElMessage.error(message) // 提示错误消息
      return Promise.reject(new Error(message))
    }
  },
  error => {
    // TODO: 将来处理 token 超时问题
    ElMessage.error(error.message) // 提示错误信息
    return Promise.reject(error)
  }
)

export default service

这时,我们需要对 vuex 中的 user 模块进行一下处理

this.commit('user/setToken', data.token)

登录鉴权解决方案

完成上边这些,登录相关的就只剩下鉴权这一部分了,在进行鉴权处理之前我们需要先创建一个登录后的跳转页面

1、创建 layout/index.vue

<template>
  <div>Layout 页面</div>
</template>

<script setup>
import {} from 'vue'
</script>

<style lang="scss" scoped></style>

2、在 router/index 中,指定对应的路由表

const publicRoutes = [
  {
    path: '/',
    component: () => import('@/layout/index')
  }
]

3、登录后进行跳转

// 登录后操作
router.push('/')

处理完这个页面,我们就开始处理登录鉴权,那么什么是登录鉴权呢

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

想要实现这个功能,我们需要通过路由守卫进行实现

main.js 同级创建 permission.js

import router from './router'
import store from './store'

// 白名单
const whiteList = ['/login']
/**
 * 路由前置守卫
 */
router.beforeEach(async (to, from, next) => {
  // 存在 token ,进入主页
  // if (store.state.user.token) {
  // 快捷访问
  if (store.getters.token) {
    if (to.path === '/login') {
      next('/')
    } else {
      next()
    }
  } else {
    // 没有token的情况下,可以进入白名单
    if (whiteList.indexOf(to.path) > -1) {
      next()
    } else {
      next('/login')
    }
  }
})

此处,我们使用了 vuexgetters,使用其进行快捷访问

const getters = {
  token: state => state.user.token
}
export default getters

store/index 中导入

import getters from './getters'
export default createStore({
  getters,
})

最后还需要在 main.js 中引入 permission.js

到这里,整个的登录架构解决方案就已经基本完成了