1.安装vuex、axios、js-cookie、vue-router
vuex命令行:
npm install vuex@next --save
axios命令行:
npm install axios
js-cookie命令行:
npm install js-cookie
vue-router命令行:
npm install vue-router
2.配置文件
(1)缓存文件配置
src/plugins/auth.js
const sessionCache = {
set (key, value) {
if (!sessionStorage) {
return
}
if (key != null && value != null) {
sessionStorage.setItem(key, value)
}
},
get (key) {
if (!sessionStorage) {
return null
}
if (key == null) {
return null
}
return sessionStorage.getItem(key)
},
setJSON (key, jsonValue) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON (key) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove (key) {
sessionStorage.removeItem(key);
}
}
const localCache = {
set (key, value) {
if (!localStorage) {
return
}
if (key != null && value != null) {
localStorage.setItem(key, value)
}
},
get (key) {
if (!localStorage) {
return null
}
if (key == null) {
return null
}
return localStorage.getItem(key)
},
setJSON (key, jsonValue) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON (key) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove (key) {
localStorage.removeItem(key);
}
}
export default {
/**
* 会话级缓存
*/
session: sessionCache,
/**
* 本地缓存
*/
local: localCache
}
(2)js-cookie文件配置
src/utils/auth.js
import Cookies from 'js-cookie'
const TokenKey = 'Admin-gis-jcpt-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
(3)axios文件配置
src/utils/axiosHttp.js
import axios from "axios";
import { getToken } from '@/utils/auth';
import cache from '@/plugins/cache';
import store from "@/store";
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';// 传参方式json
//axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';//传参方式表单
// 设置接口超时时间
const timeout = 60000;
// 设置请求地址
const baseURL = 'http://192.168.1.167:8080/gis_jcpt';
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
//baseURL: process.env.VUE_APP_BASE_API,
baseURL:baseURL,
// 超时
timeout: timeout
})
// http request 请求拦截器
service.interceptors.request.use(config =>{
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
if (getToken() && !isToken) {
//console.log("getToken",getToken());
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
return config;
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config;
},
error =>{
console.log(error)
return Promise.reject(error);
}
)
// http response 响应拦截器
service.interceptors.response.use(response =>{
// 未设置状态码则默认成功状态
const code = response.data.code || 200;
const msg = response.data.msg || '请求错误';
if(code === 401){
// 登录状态过期-退出
store.dispatch('Logout').then(()=>{
location.href = '/';
})
}else if(code === 500){
return Promise.reject(new Error(msg));
}else if(code === 601){
//
return Promise.reject('error');
}else if(code !== 200){
return Promise.reject('error');
}else {
return response.data;
}
},
error =>{
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
console.log("message",message);
return Promise.reject(error)
}
)
export default service;
登录请求为例:
src/api/login.js
import request from "@/utils/axiosHttp";
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
}
return request({
url: '/login',
headers: {
isToken: false,
repeatSubmit: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
}
// 退出方法
export function logout() {
return request({
url: '/logout',
method: 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/captchaImage',
headers: {
isToken: false,
},
method: 'get',
timeout: 20000
})
}
(4)vuex文件配置:
src/store/index.js
// store/index.js
import { createStore } from 'vuex';
import {login, logout, getInfo} from '@/api/login';
import { getToken, setToken, removeToken } from '@/utils/auth'
export default createStore({
state: {
token: null,
isLoggedIn: false, // 初始状态为未登录
user: null // 存储用户信息
},
getters: {
token: state => state.token,
isLoggedIn: state => state.isLoggedIn,
user: state => state.user,
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_ID: (state, id) => {
state.id = id
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
},
setLoginStatus(state, status) {
state.isLoggedIn = status;
},
setUser(state, user) {
state.user = user;
}
},
actions: {
Login({ commit }, user) {
const username = user.username.trim();
const password = user.password;
const code = user.code;
const uuid = user.uuid;
return new Promise((resolve,reject)=>{
login(username,password,code,uuid).then(res =>{
if(res.code === 200){
setToken(res.token);
commit('SET_TOKEN', res.token);
commit('setLoginStatus', true);
// 不保存到localStorage,刷新浏览器token、isLoggedIn、user信息重置为空
localStorage.setItem('auth', JSON.stringify(user)); // 用户信息保存到localStorage
localStorage.setItem('setLoginStatus', true); // 登录成功状态保存到localStorage
resolve(true);
}else{
alert(res.data.msg);
}
}).catch(error =>{
reject(error);
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user;
// 获取头像
//const avatar = (user.avatar == "" || user.avatar == null) ? "@/assets/images/figure-1.png" : process.env.VUE_APP_BASE_API + user.avatar;
const avatar = "@/assets/images/figure-1.png";
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions)
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
commit('SET_ID', user.userId)
commit('SET_NAME', user.userName)
commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 退出系统
Logout({ commit }) {
const logoutToken = {
token:getToken(),
}
return new Promise((resolve,reject)=>{
logout(logoutToken).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
commit('SET_PERMISSIONS', [])
removeToken()
commit('setLoginStatus', false);
localStorage.removeItem('auth');// 从localStorage移除
localStorage.removeItem('setLoginStatus');// 从localStorage移除
resolve()
}).catch(error => {
reject(error)
})
})
}
}
});
(5)main.js重新配置登录状态
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
//使用mitt插件
import mitt from 'mitt'
// Vue Router
import router from '@/router'
import store from './store';
//openlayers
import 'ol/ol.css';
// 通用字体
import 'vfonts/Lato.css'
//windiCss
import 'virtual:windi.css'
const app = createApp(App);
// 从localStorage获取数据
const isLoggedIn = localStorage.getItem('setLoginStatus');// 获取登录状态
const savedUser = localStorage.getItem('auth');// 获取登录用户信息
if (savedUser) {
store.commit('setLoginStatus', isLoggedIn);
store.commit('setUser', JSON.parse(savedUser));
}
//挂载全局属性
app.config.globalProperties.$eventBus = mitt();
app.use(router)
app.use(store)
app.mount('#app')
(6)router页面
src/router/index.js
// 该文件是专门用于创建整个应用的路由器
import { createRouter, createWebHistory } from "vue-router";
import Home from "@/views/Home.vue";
import Login from "@/views/Login.vue";
import store from '@/store'; // 引入 Vuex store
const routes = [
{ path: "/", component: Login},
{ path: "/login",name: "login", component: Login },
// { path: "/login", name: "login", component: Login },
{ path: "/index", name: "index", component: Home,meta: { requiresAuth: true } },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({ path: '/login' }); // 如果用户未认证,则重定向到登录页面
} else {
next(); // 如果用户已认证,则允许访问该页面
}
} else {
next(); // 确保其他不需要认证的页面可以正常访问
}
})
// 创建router实例对象并暴露
export default router;
3.使用示例
登录:
***
***
<script setup>
import {onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex';
import { _service } from '@/api';
import { useRequest } from 'alova/client';
import {getCodeImg} from '@/api/login';
const router = useRouter()
const store = useStore();
const code = ref('');
const codeUrl = ref('');
const uuid = ref('');
const username = ref('admin');
const password = ref('xxzxadmin');
// 验证码开关
const captchaEnabled = ref('');
onMounted(()=>{
getCode();
});
// 获取验证码
const getCode = async() =>{
getCodeImg().then(res => {
//console.log("res",res);
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
uuid.value = res.uuid;
}
});
}
// 登录方法
const loginHandle = () => {
// router.push('/')
const user = {
username: username.value,
password: password.value,
code: code.value,
uuid: uuid.value
};
store.dispatch('Login', user).then((isLogin) => {
if(isLogin){
// 登录成功后跳转到首页或其他页面
router.push('/index');
}
}).catch((error) => {
console.error('Login failed:', error);
alert(error);
// 调用获取验证码方法
getCode();
});
}
</script>
***
***
获取用户信息:
onMounted(()=>{
// 获取用户信息
store.dispatch('GetInfo').then((res)=>{
console.log("GetInfo",res);
})
})
退出:
***
***
<script setup>
import { useRouter } from 'vue-router';
import store from "@/store";
const router = useRouter()
// 退出按钮
const logout = () =>{
// 退出
store.dispatch('Logout').then(()=>{
// 退出成功后跳转到登录页面
//router.push('/');
// 跳转到退出页面(当前页面打开URL页面)
location.href = '/';
})
}
</script>
***
***
后台为若依