fix: 修复页面刷新导致丢失权限的问题

This commit is contained in:
gaoyunqi
2024-02-27 15:19:54 +08:00
parent d524aef472
commit cb075df41c
3 changed files with 413 additions and 414 deletions

View File

@ -1,68 +1,66 @@
import type { Router } from 'vue-router'; import type { Router } from 'vue-router';
import { configureDynamicParamsMenu } from '../helper/menuHelper'; import { configureDynamicParamsMenu } from '../helper/menuHelper';
import { Menu } from '../types'; import { Menu } from '../types';
import { PermissionModeEnum } from '/@/enums/appEnum'; import { PermissionModeEnum } from '/@/enums/appEnum';
import { useAppStoreWithOut } from '/@/store/modules/app'; import { useAppStoreWithOut } from '/@/store/modules/app';
import { usePermissionStoreWithOut } from '/@/store/modules/permission'; import { usePermissionStoreWithOut } from '/@/store/modules/permission';
export function createParamMenuGuard(router: Router) { export function createParamMenuGuard(router: Router) {
const permissionStore = usePermissionStoreWithOut(); const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, _, next) => { router.beforeEach(async (to, _, next) => {
console.log('createParamMenuGuard', to); to.fullPath = (to.fullPath as string) + convertQuery(to);
to.fullPath = (to.fullPath as string) + convertQuery(to); // filter no name route
if (!to.name) {
// filter no name route next();
if (!to.name) { return;
next(); }
return;
} // menu has been built.
if (!permissionStore.getIsDynamicAddedRoute) {
// menu has been built. next();
if (!permissionStore.getIsDynamicAddedRoute) { return;
next(); }
return;
} let menus: Menu[] = [];
if (isBackMode()) {
let menus: Menu[] = []; menus = permissionStore.getBackMenuList;
if (isBackMode()) { } else if (isRouteMappingMode()) {
menus = permissionStore.getBackMenuList; menus = permissionStore.getFrontMenuList;
} else if (isRouteMappingMode()) { }
menus = permissionStore.getFrontMenuList; menus.forEach((item) => configureDynamicParamsMenu(item, to.params));
}
menus.forEach((item) => configureDynamicParamsMenu(item, to.params)); next();
});
next(); }
});
} const convertQuery = (to) => {
try {
const convertQuery = (to) => { if (to.meta.remark && to.meta.remark.indexOf('?') > -1 && to.fullPath.indexOf('?') <= -1) {
try { const str = to.meta.remark.substring(1);
if (to.meta.remark && to.meta.remark.indexOf('?') > -1 && to.fullPath.indexOf('?') <= -1) { const paramArray = str.split('&');
const str = to.meta.remark.substring(1); for (const param of paramArray) {
const paramArray = str.split('&'); const p = param.split('=');
for (const param of paramArray) { to.query[p[0]] = p[1];
const p = param.split('='); }
to.query[p[0]] = p[1]; return to.meta.remark;
} }
return to.meta.remark; return '';
} } catch {
return ''; return '';
} catch { }
return ''; };
}
}; const getPermissionMode = () => {
const appStore = useAppStoreWithOut();
const getPermissionMode = () => { return appStore.getProjectConfig.permissionMode;
const appStore = useAppStoreWithOut(); };
return appStore.getProjectConfig.permissionMode;
}; const isBackMode = () => {
return getPermissionMode() === PermissionModeEnum.BACK;
const isBackMode = () => { };
return getPermissionMode() === PermissionModeEnum.BACK;
}; const isRouteMappingMode = () => {
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
const isRouteMappingMode = () => { };
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
};

View File

@ -1,117 +1,117 @@
import type { Router, RouteRecordRaw } from 'vue-router'; import type { Router, RouteRecordRaw } from 'vue-router';
import { usePermissionStoreWithOut } from '/@/store/modules/permission'; import { usePermissionStoreWithOut } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { useUserStoreWithOut } from '/@/store/modules/user'; import { useUserStoreWithOut } from '/@/store/modules/user';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { RootRoute } from '/@/router/routes'; import { RootRoute } from '/@/router/routes';
const LOGIN_PATH = PageEnum.BASE_LOGIN; const LOGIN_PATH = PageEnum.BASE_LOGIN;
const ROOT_PATH = RootRoute.path; const ROOT_PATH = RootRoute.path;
const whitePathList: PageEnum[] = [LOGIN_PATH]; const whitePathList: PageEnum[] = [LOGIN_PATH];
export function createPermissionGuard(router: Router) { export function createPermissionGuard(router: Router) {
const userStore = useUserStoreWithOut(); const userStore = useUserStoreWithOut();
const permissionStore = usePermissionStoreWithOut(); const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
if ( if (
from.path === ROOT_PATH && from.path === ROOT_PATH &&
to.path === PageEnum.BASE_HOME && to.path === PageEnum.BASE_HOME &&
userStore.getUserInfo.homePath && userStore.getUserInfo.homePath &&
userStore.getUserInfo.homePath !== PageEnum.BASE_HOME userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
) { ) {
next(userStore.getUserInfo.homePath); next(userStore.getUserInfo.homePath);
return; return;
} }
const token = userStore.getToken; const token = userStore.getToken;
// Whitelist can be directly entered // Whitelist can be directly entered
if (whitePathList.includes(to.path as PageEnum)) { if (whitePathList.includes(to.path as PageEnum)) {
if (to.path === LOGIN_PATH && token) { if (to.path === LOGIN_PATH && token) {
const isSessionTimeout = userStore.getSessionTimeout; const isSessionTimeout = userStore.getSessionTimeout;
try { try {
await userStore.afterLoginAction(); await userStore.afterLoginAction();
if (!isSessionTimeout) { if (!isSessionTimeout) {
next((to.query?.redirect as string) || '/'); next((to.query?.redirect as string) || '/');
return; return;
} }
} catch {} } catch {}
} }
next(); next();
return; return;
} }
// token does not exist // token does not exist
if (!token) { if (!token) {
// You can access without permission. You need to set the routing meta.ignoreAuth to true // You can access without permission. You need to set the routing meta.ignoreAuth to true
if (to.meta.ignoreAuth) { if (to.meta.ignoreAuth) {
next(); next();
return; return;
} }
// redirect login page // redirect login page
const redirectData: { path: string; replace: boolean; query?: Recordable<string> } = { const redirectData: { path: string; replace: boolean; query?: Recordable<string> } = {
path: LOGIN_PATH, path: LOGIN_PATH,
replace: true, replace: true,
}; };
if (to.path) { if (to.path) {
redirectData.query = { redirectData.query = {
...redirectData.query, ...redirectData.query,
redirect: to.path, redirect: to.path,
}; };
} }
next(redirectData); next(redirectData);
return; return;
} }
// Jump to the 404 page after processing the login // Jump to the 404 page after processing the login
if ( if (
from.path === LOGIN_PATH && from.path === LOGIN_PATH &&
to.name === PAGE_NOT_FOUND_ROUTE.name && to.name === PAGE_NOT_FOUND_ROUTE.name &&
to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME) to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)
) { ) {
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
return; return;
} }
// get userinfo while last fetch time is empty // get userinfo while last fetch time is empty
if (userStore.getLastUpdateTime === 0) { if (userStore.getLastUpdateTime === 0) {
try { try {
await userStore.getUserInfoAction(); await userStore.getUserInfoAction();
} catch (err) { } catch (err) {
next(); next();
return; return;
} }
} }
if (permissionStore.getIsDynamicAddedRoute) { if (permissionStore.getIsDynamicAddedRoute) {
next(); next();
return; return;
} }
const routes = await permissionStore.buildRoutesAction(false);
const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw); routes.forEach((route) => {
}); router.addRoute(route as unknown as RouteRecordRaw);
});
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
permissionStore.setDynamicAddedRoute(true); permissionStore.setDynamicAddedRoute(true);
if (to.name === PAGE_NOT_FOUND_ROUTE.name) { if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
// 动态添加路由后此处应当重定向到fullPath否则会加载404页面内容 // 动态添加路由后此处应当重定向到fullPath否则会加载404页面内容
next({ path: to.fullPath, replace: true, query: to.query }); next({ path: to.fullPath, replace: true, query: to.query });
} else { } else {
const redirectPath = (from.query.redirect || to.path) as string; const redirectPath = (from.query.redirect || to.path) as string;
const redirect = decodeURIComponent(redirectPath); const redirect = decodeURIComponent(redirectPath);
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }; const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
next(nextData); next(nextData);
} }
}); });
} }

View File

@ -1,229 +1,230 @@
import type { UserInfo } from '/#/store'; import type { UserInfo } from '/#/store';
import type { ErrorMessageMode } from '/#/axios'; import type { ErrorMessageMode } from '/#/axios';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { store } from '/@/store'; import { store } from '/@/store';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
import { getAuthCache, setAuthCache } from '/@/utils/auth'; import { getAuthCache, setAuthCache } from '/@/utils/auth';
import { GetUserInfoModel, LoginParams, RoleInfo } from '/@/api/system/login/model'; import { GetUserInfoModel, LoginParams, RoleInfo } from '/@/api/system/login/model';
import { doLogout, getUserInfo, loginApi } from '/@/api/system/login'; import { doLogout, getUserInfo, loginApi } from '/@/api/system/login';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { router } from '/@/router'; import { router } from '/@/router';
import { usePermissionStore } from '/@/store/modules/permission'; import { usePermissionStore } from '/@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { h } from 'vue'; import { h } from 'vue';
import { getAppEnvConfig } from '/@/utils/env'; import { getAppEnvConfig } from '/@/utils/env';
interface UserState { interface UserState {
userInfo: Nullable<UserInfo>; userInfo: Nullable<UserInfo>;
token?: string; token?: string;
roleList: RoleInfo[]; roleList: RoleInfo[];
sessionTimeout?: boolean; sessionTimeout?: boolean;
lastUpdateTime: number; lastUpdateTime: number;
} }
export const useUserStore = defineStore({ export const useUserStore = defineStore({
id: 'app-user', id: 'app-user',
state: (): UserState => ({ state: (): UserState => ({
// user info // user info
userInfo: null, userInfo: null,
// token // token
token: undefined, token: undefined,
// roleList // roleList
roleList: [], roleList: [],
// Whether the login expired // Whether the login expired
sessionTimeout: false, sessionTimeout: false,
// Last fetch time // Last fetch time
lastUpdateTime: 0, lastUpdateTime: 0,
}), }),
getters: { getters: {
getUserInfo(): UserInfo { getUserInfo(): UserInfo {
return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {}; return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
}, },
getToken(): string { getToken(): string {
return this.token || getAuthCache<string>(TOKEN_KEY); return this.token || getAuthCache<string>(TOKEN_KEY);
}, },
getRoleList(): RoleInfo[] { getRoleList(): RoleInfo[] {
return this.roleList && this.roleList.length > 0 return this.roleList && this.roleList.length > 0
? this.roleList ? this.roleList
: getAuthCache<RoleInfo[]>(ROLES_KEY); : getAuthCache<RoleInfo[]>(ROLES_KEY);
}, },
getSessionTimeout(): boolean { getSessionTimeout(): boolean {
return !!this.sessionTimeout; return !!this.sessionTimeout;
}, },
getLastUpdateTime(): number { getLastUpdateTime(): number {
return this.lastUpdateTime; return this.lastUpdateTime;
}, },
}, },
actions: { actions: {
setToken(info: string | undefined) { setToken(info: string | undefined) {
this.token = info ? info : ''; // for null or undefined value this.token = info ? info : ''; // for null or undefined value
setAuthCache(TOKEN_KEY, info); setAuthCache(TOKEN_KEY, info);
}, },
setRoleList(roleList: RoleInfo[]) { setRoleList(roleList: RoleInfo[]) {
this.roleList = roleList; this.roleList = roleList;
setAuthCache(ROLES_KEY, roleList); setAuthCache(ROLES_KEY, roleList);
}, },
setUserInfo(info: UserInfo | null) { setUserInfo(info: UserInfo | null) {
this.userInfo = info; this.userInfo = info;
this.lastUpdateTime = new Date().getTime(); this.lastUpdateTime = new Date().getTime();
setAuthCache(USER_INFO_KEY, info); setAuthCache(USER_INFO_KEY, info);
}, },
setSessionTimeout(flag: boolean) { setSessionTimeout(flag: boolean) {
this.sessionTimeout = flag; this.sessionTimeout = flag;
}, },
resetState() { resetState() {
this.userInfo = null; this.userInfo = null;
this.token = ''; this.token = '';
this.roleList = []; this.roleList = [];
this.sessionTimeout = false; this.sessionTimeout = false;
}, },
/** /**
* @description: OAUTH Login * @description: OAUTH Login
*/ */
async oauthLogin( async oauthLogin(
params: { params: {
token: string; token: string;
} & { } & {
goHome?: boolean; goHome?: boolean;
mode?: ErrorMessageMode; mode?: ErrorMessageMode;
}, },
): Promise<GetUserInfoModel | null> { ): Promise<GetUserInfoModel | null> {
try { try {
const { goHome = true, token } = params; const { goHome = true, token } = params;
// save token // save token
this.setToken(token); this.setToken(token);
return this.afterLoginAction(goHome); return this.afterLoginAction(goHome);
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
} }
}, },
/** /**
* @description: login * @description: login
*/ */
async login( async login(
params: LoginParams & { params: LoginParams & {
goHome?: boolean; goHome?: boolean;
mode?: ErrorMessageMode; mode?: ErrorMessageMode;
}, },
): Promise<GetUserInfoModel | null> { ): Promise<GetUserInfoModel | null> {
try { try {
const { goHome = true, mode, ...loginParams } = params; const { goHome = true, mode, ...loginParams } = params;
const data = await loginApi(loginParams, mode); const data = await loginApi(loginParams, mode);
const { token } = data; const { token } = data;
// save token // save token
this.setToken(token); this.setToken(token);
return this.afterLoginAction(goHome); return await this.afterLoginAction(goHome);
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
} }
}, },
async afterLoginAction(goHome?: boolean): Promise<GetUserInfoModel | null> { async afterLoginAction(goHome?: boolean): Promise<GetUserInfoModel | null> {
if (!this.getToken) return null; if (!this.getToken) return null;
// get user info // get user info
const userInfo = await this.getUserInfoAction(); const userInfo = await this.getUserInfoAction();
// setOtherToken(this.getToken); // setOtherToken(this.getToken);
const sessionTimeout = this.sessionTimeout; const sessionTimeout = this.sessionTimeout;
if (sessionTimeout) { if (sessionTimeout) {
this.setSessionTimeout(false); this.setSessionTimeout(false);
} else { } else {
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
if (!permissionStore.isDynamicAddedRoute) { if (!permissionStore.getIsDynamicAddedRoute) {
const routes = await permissionStore.buildRoutesAction(); permissionStore.setDynamicAddedRoute(true);
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw); const routes = await permissionStore.buildRoutesAction();
}); routes.forEach((route) => {
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); router.addRoute(route as unknown as RouteRecordRaw);
permissionStore.setDynamicAddedRoute(true); });
} router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME)); }
} goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME));
}
setOtherToken(this.getToken);
return Promise.resolve(userInfo); setOtherToken(this.getToken);
}, return Promise.resolve(userInfo);
async getUserInfoAction(): Promise<GetUserInfoModel | null> { },
if (!this.getToken) return null; async getUserInfoAction(): Promise<GetUserInfoModel | null> {
const userInfoResult = await getUserInfo(); if (!this.getToken) return null;
const userInfoResult = await getUserInfo();
const { roles = [] } = userInfoResult;
const { roles = [] } = userInfoResult;
const userInfo = userInfoResult as unknown as UserInfo;
this.setUserInfo(userInfo); const userInfo = userInfoResult as unknown as UserInfo;
this.setRoleList(roles); this.setUserInfo(userInfo);
return Promise.resolve(userInfoResult); this.setRoleList(roles);
}, return Promise.resolve(userInfoResult);
/** },
* @description: logout /**
*/ * @description: logout
async logout(goLogin = false) { */
if (this.getToken) { async logout(goLogin = false) {
try { if (this.getToken) {
await doLogout(); try {
} catch { await doLogout();
console.log('注销Token失败'); } catch {
} console.log('注销Token失败');
} }
this.setToken(undefined); }
this.setSessionTimeout(false); this.setToken(undefined);
this.setUserInfo(null); this.setSessionTimeout(false);
goLogin && router.push(PageEnum.BASE_LOGIN); this.setUserInfo(null);
}, goLogin && router.push(PageEnum.BASE_LOGIN);
},
/**
* @description: Confirm before logging out /**
*/ * @description: Confirm before logging out
confirmLoginOut() { */
const { createConfirm } = useMessage(); confirmLoginOut() {
const { t } = useI18n(); const { createConfirm } = useMessage();
createConfirm({ const { t } = useI18n();
iconType: 'warning', createConfirm({
title: () => h('span', t('温馨提醒')), iconType: 'warning',
content: () => h('span', t('是否确认退出系统?')), title: () => h('span', t('温馨提醒')),
onOk: async () => { content: () => h('span', t('是否确认退出系统?')),
await this.logout(true); onOk: async () => {
}, await this.logout(true);
okText: () => t('确认'), },
cancelText: () => t('取消'), okText: () => t('确认'),
}); cancelText: () => t('取消'),
}, });
}, },
}); },
});
// Need to be used outside the setup
export function useUserStoreWithOut() { // Need to be used outside the setup
return useUserStore(store); export function useUserStoreWithOut() {
} return useUserStore(store);
}
//设置其他url 项目 token
function setOtherToken(token: string) { //设置其他url 项目 token
// console.log('other token', getAppEnvConfig()); // something like: "https://codegeex.cn" or "https://codegeex.cn" or function setOtherToken(token: string) {
getAppEnvConfig() // console.log('other token', getAppEnvConfig()); // something like: "https://codegeex.cn" or "https://codegeex.cn" or
.VITE_GLOB_OUT_LINK_URL?.split(',') getAppEnvConfig()
?.forEach((item) => { .VITE_GLOB_OUT_LINK_URL?.split(',')
// 创建子域的iframe, 用于传送数据 ?.forEach((item) => {
const iframe = document.createElement('iframe'); // 创建子域的iframe, 用于传送数据
iframe.src = `${item}`; const iframe = document.createElement('iframe');
iframe.style.display = 'none'; iframe.src = `${item}`;
document.body.append(iframe); iframe.style.display = 'none';
document.body.append(iframe);
// 使用postMessage()发送数据到子系统
setTimeout(function () { // 使用postMessage()发送数据到子系统
iframe.contentWindow?.postMessage(token, item); setTimeout(function () {
}, 2000); iframe.contentWindow?.postMessage(token, item);
}, 2000);
// 销毁iframe
setTimeout(function () { // 销毁iframe
iframe.remove(); setTimeout(function () {
}, 4000); iframe.remove();
}); }, 4000);
} });
}