后台管理系统之登录方案记录
需求:根据当前环境的不同,请求不同的 BaseUrl
解决:在根目录中新建.env.development与.env.production连个文件,进行配置:
# .env.production
ENV = 'production'# base api
VUE_APP_BASE_API = '/prod-api'# .env.development
ENV = 'development'# base api
VUE_APP_BASE_API = '/api'
然后在utils/request.js中配置:
import axios from 'axios'const service = axios.create({//process.env 表示当前环境下的所有环境变量baseURL: process.env.VUE_APP_BASE_API, timeout: 5000
})export default service
问题:
出现这个问题的原因,是因为我们在前面配置环境变量时指定了 开发环境下,请求的 BaseUrl
为 /api;
这样的一个请求会被自动键入到当前前端所在的服务中,所以我们最终就得到了 http://192.168.18.42:8081/api/sys/login
这样的一个请求路径
解决:通过指定 webpack DevServer 代理 的形式,代理当前的 url
请求;在vue.config.js中进行如下编辑
module.exports = {devServer: {// 配置反向代理proxy: {// 当地址中有/api的时候会触发代理机制'/api': {// 要代理的服务器地址 这里不用写 apitarget: 'https://api.xxxxxxx.club/',changeOrigin: true // 是否跨域}}},xxxxxxxxx
}
在vuex中进行请求处理
创建 api
文件夹,创建 sys.js
,配置请求:
import request from '@/utils/request'/*** 登录*/
export const login = data => {return request({url: '/sys/login',method: 'POST',data})
}
将封装登录请求处理封装到 vuex
的 action
中。在 store
下创建 modules
文件夹,创建 user.js
模块,进行请求处理:
import { login } from '@/api/sys'
import md5 from 'md5'
export default {namespaced: true,state: () => ({}),mutations: {},actions: {login(context, userInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({username,// md5用来将密码加密处理password: md5(password)}).then(data => {resolve()}).catch(err => {reject(err)})})}}
}
在 store/index
中完成注册:
import { createStore } from 'vuex'
import user from './modules/user.js'
export default createStore({modules: {user}
})
在 login
中,触发定义的 action
:
<template>xxxxxx</template>
<script setup>
import { useStore } from "vuex";const store = useStore();
const handleLogin = () => {//先校验数据,校验省略,数据格式校验通过进行登录store.dispatch("user/login", loginForm.value).then(() => {// TODO: 登录后操作}).catch((err) => {console.log(err);});
};
</script>
本地缓存处理方案
创建 utils/storage.js
文件,封装对本地LocalStorage的操作:注意两种不同数据类型的处理
/*** 存储数据*/
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()
}
创建 constant
常量目录 constant/index.js
:
export const TOKEN = 'token'
在 vuex
的 user
模块下,处理 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 = tokensetItem(TOKEN, token)}},actions: {login(context, userInfo) {....then(data => {this.commit('user/setToken', data.data.data.token)resolve()})...})}}
}
通过axios响应拦截器处理data.data.data.token问题。在 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)
登录鉴权
当用户未登陆时,不允许进入除 login
之外的其他页面。用户登录后,token
未过期之前,不允许进入 login
页面
根目录创建permission.js,并在main.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')}}
})
在此处的 getters
被当作 快捷访问 的形式进行访问,所以我们需要声明对应的模块,创建 store/getters
const getters = {token: state => state.user.token
}
export default getters
在 store/index
中进行导入:
import getters from './getters'
export default createStore({getters,...
})