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

news/2024/7/10 0:56:02 标签: 学习, vue

配置登陆解决方案

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

配置环境变量

在根目录创建开发模式和生产模式的两种baseURL
在这里插入图片描述
输入:

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模块,用于处理所有与用户相关的内容。
在这里插入图片描述

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文件

在这里插入图片描述
在main.js导入
在这里插入图片描述
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
}

登录成功后设置时间戳,保存登录时间 -> 跳转页面 ,在每次请求接口时检查时间是否超时:
在这里插入图片描述


http://www.niftyadmin.cn/n/5036491.html

相关文章

使用 LangChain 和 Elasticsearch 对私人数据进行人工智能搜索

关于本博文的所有代码可以在地址下载:GitHub - liu-xiao-guo/python-vector-private 我将在本博文中其中深入研究人工智能和向量嵌入的深水区。 ChatGPT 令人大开眼界,但有一个主要问题。 这是一个封闭的托管系统。 在一个被大型网络公司改变的世界里生…

玩转Mysql系列 - 第22篇:mysql索引原理详解

这是Mysql系列第22篇。 背景 使用mysql最多的就是查询,我们迫切的希望mysql能查询的更快一些,我们经常用到的查询有: 按照id查询唯一一条记录 按照某些个字段查询对应的记录 查找某个范围的所有记录(between and) …

【2023年11月第四版教材】第13章《资源管理》(合集篇)

第13章《资源管理》(合集篇) 1 章节说明2 管理基础2.1 术语2.2 项目经理的权力有5种来源2.3 优秀团 队的建设5个阶段2.4 激励理论2.4.1 马斯洛需求层次理论2.4.2 赫茨伯格双因素理论:★★★2.4.3 X理论(不好)步丫理论&…

前端开发之el-table 表头不换行且宽度自适应

element的table中动态添加表头并设置表头不换行 前言效果图element中使用代码 element-plus中使用:没有了h代码 前言 本次讲解的是elemen和element-plus来通过table的标签render-header来实现的 效果图 element中使用 代码 <template><div><el-table :data&q…

Go 语言学习总结(9)—— Go 与 Java 全面对比总结

基本语法格式 Golang: 编码风格相对统一&#xff0c;简单&#xff0c;没有太多的语法糖等&#xff0c;Java层次清晰&#xff0c;全面面向对象。 变量相关 变量的声明及使用 在Java或者PHP、Python中&#xff0c;声明了变量&#xff0c;可以不使用&#xff0c;也不报错。 p…

使用Caffeine做JVM缓存,提升字典类查询性能

业务场景 对于字典值&#xff0c;一般只存code&#xff0c;名称则查询时去查字典&#xff0c;返回给前端展示。那么就会存在jvm中多次调用字典查询的问题&#xff0c;为了提高性能&#xff0c;对字典进行jvm缓存。 示例代码 Caffeine创建缓存&#xff0c;有效期为5分钟&#x…

uni-app实现点击复制按钮 复制内容

注意:uni.setClipboardData({})里面的data参数必须是字符串类型这个是大坑 第一种 <view>{{orderId}}</view> //复制的内容 <button click"copy(orderId)">复制</button>copy(value) {uni.setClipboardData({data: value , // 这里是个坑接…

Maven高级---聚合(如何将SpringBoot项目打包上线)

目录 Maven集合要解决的问题 解决办法-Maven聚合 总结 Maven集合要解决的问题 情景:项目已经开发完毕,要将该management工程打包上线. 此时我们点击Maven的打包按钮 但结果是构建失败,提示如下 原因:执行打包时他会在本地仓库中寻找模块,然而Maven本地仓库中并没有这两个模块…