刷新多此会跳转到登陆的问题解决了,但是刷新会出现更逆天的问题
This commit is contained in:
parent
f905a984f2
commit
c6c6df9c57
@ -13,12 +13,13 @@ const axiosInstance = axios.create({
|
|||||||
timeout: 10000
|
timeout: 10000
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
export function setupInterceptors() {
|
||||||
|
/**
|
||||||
* 请求拦截器
|
* 请求拦截器
|
||||||
* - 对需要认证的请求,在请求头中添加Authorization
|
* - 对需要认证的请求,在请求头中添加Authorization
|
||||||
* - 对登录、注册和获取列表的请求,不添加Authorization
|
* - 对登录、注册和获取列表的请求,不添加Authorization
|
||||||
*/
|
*/
|
||||||
axiosInstance.interceptors.request.use(
|
axiosInstance.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
const token = localStorage.getItem('access_token');
|
const token = localStorage.getItem('access_token');
|
||||||
const url = config.url;
|
const url = config.url;
|
||||||
@ -26,8 +27,7 @@ axiosInstance.interceptors.request.use(
|
|||||||
// 定义不需要Token的接口条件
|
// 定义不需要Token的接口条件
|
||||||
const noAuthRequired =
|
const noAuthRequired =
|
||||||
url === '/user/login' ||
|
url === '/user/login' ||
|
||||||
url === '/user/register' || // 明确添加注册接口
|
url === '/user/register';
|
||||||
url.endsWith('/getlist');
|
|
||||||
|
|
||||||
if (token && !noAuthRequired) {
|
if (token && !noAuthRequired) {
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
@ -37,13 +37,13 @@ axiosInstance.interceptors.request.use(
|
|||||||
error => {
|
error => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应拦截器
|
* 响应拦截器
|
||||||
* - 如果收到401错误(未授权),并且不是来自登录请求,则调用logoutUser函数清除用户凭证
|
* - 如果收到401错误(未授权),并且不是来自登录请求,则调用logoutUser函数清除用户凭证
|
||||||
*/
|
*/
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
response => response,
|
response => response,
|
||||||
error => {
|
error => {
|
||||||
const originalRequest = error.config;
|
const originalRequest = error.config;
|
||||||
@ -55,6 +55,7 @@ axiosInstance.interceptors.response.use(
|
|||||||
// 不需要额外的console.error,错误会自然地在调用处被捕获或显示在网络请求中
|
// 不需要额外的console.error,错误会自然地在调用处被捕获或显示在网络请求中
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default axiosInstance;
|
export default axiosInstance;
|
@ -112,9 +112,6 @@ const refreshCaptcha = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
refreshCaptcha()
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
try {
|
try {
|
||||||
@ -203,6 +200,11 @@ const validateForm = () => {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
refreshCaptcha()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -2,7 +2,13 @@ import { createApp } from 'vue'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import './assets/styles/common.css'
|
import './assets/styles/common.css'
|
||||||
|
import { setupInterceptors } from './api/axiosConfig'; // 导入拦截器设置函数
|
||||||
|
|
||||||
|
// 在应用初始化最开始就设置好拦截器
|
||||||
|
setupInterceptors();
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import { hasValidToken, getUserInfo, logoutUser } from '../utils/jwt';
|
import { hasValidToken, getUserInfo, logoutUser, getStoredUser } from '../utils/jwt';
|
||||||
import { justLoggedIn } from '../utils/authSessionState';
|
import { justLoggedIn } from '../utils/authSessionState';
|
||||||
import EditorsMaps from '@/views/index/EditorsMaps.vue'
|
import EditorsMaps from '@/views/index/EditorsMaps.vue'
|
||||||
|
|
||||||
@ -113,40 +113,44 @@ const router = createRouter({
|
|||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
|
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
|
||||||
|
|
||||||
if (requiresAuth) {
|
if (!requiresAuth) {
|
||||||
const tokenExists = hasValidToken();
|
return next(); // 如果页面不需要认证,直接放行
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方案1: 检查SessionStorage中是否已有用户信息 (刷新后最先检查这里)
|
||||||
|
if (getStoredUser()) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方案2: 如果刚登录过,直接放行
|
||||||
if (justLoggedIn.value) {
|
if (justLoggedIn.value) {
|
||||||
justLoggedIn.value = false;
|
justLoggedIn.value = false;
|
||||||
if (tokenExists) {
|
// 此时token肯定有效,但可能还没来得及请求用户信息
|
||||||
next();
|
// 为确保用户信息被存储,可以调用一次,但不阻塞导航
|
||||||
} else {
|
getUserInfo().catch(err => console.error("Error fetching user info after login:", err));
|
||||||
logoutUser();
|
return next();
|
||||||
next({ path: '/backend/login', query: { redirect: to.fullPath, sessionExpired: 'true' }});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenExists) {
|
// 方案3: 检查localStorage中是否有token (刷新后SessionStorage没有用户信息时)
|
||||||
const user = await getUserInfo();
|
if (hasValidToken()) {
|
||||||
if (user) {
|
try {
|
||||||
next();
|
await getUserInfo(); // 尝试获取用户信息,该函数会把用户信息存入SessionStorage
|
||||||
} else {
|
return next(); // 获取成功,放行
|
||||||
logoutUser();
|
} catch (error) {
|
||||||
next({
|
// 获取失败 (token无效, 网络问题等)
|
||||||
|
logoutUser(); // 清除所有凭证
|
||||||
|
return next({
|
||||||
path: '/backend/login',
|
path: '/backend/login',
|
||||||
query: { redirect: to.fullPath, sessionExpired: 'true' }
|
query: { redirect: to.fullPath, sessionExpired: 'true' }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
next({
|
|
||||||
|
// 方案4: 如果以上条件都不满足,跳转登录页
|
||||||
|
return next({
|
||||||
path: '/backend/login',
|
path: '/backend/login',
|
||||||
query: { redirect: to.fullPath }
|
query: { redirect: to.fullPath }
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router
|
export default router
|
@ -4,6 +4,23 @@ import { justLoggedIn } from './authSessionState'; // Import the flag
|
|||||||
|
|
||||||
const USER_INFO_URL = '/user'; // 获取用户信息的API端点
|
const USER_INFO_URL = '/user'; // 获取用户信息的API端点
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 sessionStorage 中安全地读取和解析用户信息。
|
||||||
|
* @returns {Object|null} 用户信息对象或null。
|
||||||
|
*/
|
||||||
|
export const getStoredUser = () => {
|
||||||
|
const storedUser = sessionStorage.getItem('currentUser');
|
||||||
|
if (storedUser) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(storedUser);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing stored user info:', e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查Token是否存在且(理论上)是否在有效期内。
|
* 检查Token是否存在且(理论上)是否在有效期内。
|
||||||
* 服务端 /user接口会验证实际有效期。
|
* 服务端 /user接口会验证实际有效期。
|
||||||
@ -22,24 +39,18 @@ export const hasValidToken = () => {
|
|||||||
*/
|
*/
|
||||||
export const getUserInfo = async () => {
|
export const getUserInfo = async () => {
|
||||||
if (!hasValidToken()) {
|
if (!hasValidToken()) {
|
||||||
console.log(' No token found, skipping getUserInfo.');
|
throw new Error('No valid token found');
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// console.log('jwt.js: Attempting to fetch user info from', USER_INFO_URL);
|
|
||||||
const response = await axiosInstance.get(USER_INFO_URL);
|
const response = await axiosInstance.get(USER_INFO_URL);
|
||||||
if (response.status !== 200) {
|
const user = response.data;
|
||||||
router.push('/backend/login');
|
// 将获取到的用户信息存入 sessionStorage
|
||||||
return null;
|
sessionStorage.setItem('currentUser', JSON.stringify(user));
|
||||||
}
|
return user;
|
||||||
// console.log('jwt.js: User info received:', response.data);
|
|
||||||
return response.data;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
router.push('/backend/login');
|
// 清除可能存在的无效用户信息
|
||||||
// console.error('jwt.js: Error fetching user info:', error.response ? error.response.status : error.message);
|
sessionStorage.removeItem('currentUser');
|
||||||
// 401错误会被响应拦截器处理(清除token),然后错误会传播到这里
|
throw error;
|
||||||
// 其他网络错误等也会被捕获
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,6 +62,7 @@ export const logoutUser = () => { // 不再是 async,因为它不执行异步
|
|||||||
// console.log('jwt.js: logoutUser called. Clearing local storage.');
|
// console.log('jwt.js: logoutUser called. Clearing local storage.');
|
||||||
localStorage.removeItem('access_token');
|
localStorage.removeItem('access_token');
|
||||||
localStorage.removeItem('user_id');
|
localStorage.removeItem('user_id');
|
||||||
|
sessionStorage.removeItem('currentUser'); // 同时清除sessionStorage中的用户信息
|
||||||
// 导航将由调用者(如路由守卫)处理
|
// 导航将由调用者(如路由守卫)处理
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user