refactor: permission (#357)

* refactor: permission

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* fix: 修复`mix`混合模式导航在生产环境左侧菜单一定机率不显示的问题

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update

* chore: update
This commit is contained in:
RealityBoy
2022-10-25 12:17:13 +08:00
committed by GitHub
parent cedc84d31a
commit 6ef4cf9fb6
47 changed files with 605 additions and 386 deletions

View File

@@ -2,8 +2,8 @@ import { getConfig } from "/@/config";
import { toRouteType } from "./types";
import NProgress from "/@/utils/progress";
import { findIndex } from "lodash-unified";
import type { StorageConfigs } from "/#/index";
import { transformI18n } from "/@/plugins/i18n";
import { sessionKey, type DataInfo } from "/@/utils/auth";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import {
@@ -15,6 +15,7 @@ import {
import {
ascending,
initRouter,
isOneOfArray,
getHistoryMode,
findRouteByPath,
handleAliveRoute,
@@ -121,10 +122,10 @@ router.beforeEach((to: toRouteType, _from, next) => {
handleAliveRoute(newMatched);
}
}
const name = storageSession.getItem<StorageConfigs>("info");
const userInfo = storageSession.getItem<DataInfo<number>>(sessionKey);
NProgress.start();
const externalLink = isUrl(to?.name as string);
if (!externalLink)
if (!externalLink) {
to.matched.some(item => {
if (!item.meta.title) return "";
const Title = getConfig().Title;
@@ -132,7 +133,12 @@ router.beforeEach((to: toRouteType, _from, next) => {
document.title = `${transformI18n(item.meta.title)} | ${Title}`;
else document.title = transformI18n(item.meta.title);
});
if (name) {
}
if (userInfo) {
// 无权限跳转403页面
if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
next({ path: "/error/403" });
}
if (_from?.name) {
// name为超链接
if (externalLink) {
@@ -143,8 +149,11 @@ router.beforeEach((to: toRouteType, _from, next) => {
}
} else {
// 刷新
if (usePermissionStoreHook().wholeMenus.length === 0)
initRouter(name.username).then((router: Router) => {
if (
usePermissionStoreHook().wholeMenus.length === 0 &&
to.path !== "/login"
)
initRouter().then((router: Router) => {
if (!useMultiTagsStoreHook().getMultiTagsCache) {
const { path } = to;
const index = findIndex(remainingRouter, v => {

View File

@@ -6,7 +6,7 @@ const errorRouter: RouteConfigsTable = {
redirect: "/error/403",
meta: {
icon: "information-line",
title: $t("menus.hserror"),
title: $t("menus.hsabnormal"),
rank: 9
},
children: [

View File

@@ -2,6 +2,7 @@ import { RouteLocationNormalized } from "vue-router";
export interface toRouteType extends RouteLocationNormalized {
meta: {
roles: Array<string>;
keepAlive?: boolean;
dynamicLevel?: string;
};

View File

@@ -9,10 +9,16 @@ import {
import { router } from "./index";
import { isProxy, toRaw } from "vue";
import { loadEnv } from "../../build";
import { cloneDeep } from "lodash-unified";
import { useTimeoutFn } from "@vueuse/core";
import { RouteConfigs } from "/@/layout/types";
import { buildHierarchyTree } from "@pureadmin/utils";
import {
isString,
storageSession,
buildHierarchyTree,
isIncludeAllChildren
} from "@pureadmin/utils";
import { cloneDeep, intersection } from "lodash-unified";
import { sessionKey, type DataInfo } from "/@/utils/auth";
import { usePermissionStoreHook } from "/@/store/modules/permission";
const IFrame = () => import("/@/layout/frameView.vue");
// https://cn.vitejs.dev/guide/features.html#glob-import
@@ -38,7 +44,7 @@ function ascending(arr: any[]) {
);
}
/** 过滤meta中showLink为false的路由 */
/** 过滤meta中showLink为false的菜单 */
function filterTree(data: RouteComponent[]) {
const newTree = cloneDeep(data).filter(
(v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false
@@ -49,6 +55,37 @@ function filterTree(data: RouteComponent[]) {
return newTree;
}
/** 过滤children长度为0的的目录当目录下没有菜单时会过滤此目录目录没有赋予roles权限当目录下只要有一个菜单有显示权限那么此目录就会显示 */
function filterChildrenTree(data: RouteComponent[]) {
const newTree = cloneDeep(data).filter((v: any) => v?.children?.length !== 0);
newTree.forEach(
(v: { children }) => v.children && (v.children = filterTree(v.children))
);
return newTree;
}
/** 判断两个数组彼此是否存在相同值 */
function isOneOfArray(a: Array<string>, b: Array<string>) {
return Array.isArray(a) && Array.isArray(b)
? intersection(a, b).length > 0
? true
: false
: true;
}
/** 从sessionStorage里取出当前登陆用户的角色roles过滤无权限的菜单 */
function filterNoPermissionTree(data: RouteComponent[]) {
const currentRoles =
storageSession.getItem<DataInfo<number>>(sessionKey).roles ?? [];
const newTree = cloneDeep(data).filter((v: any) =>
isOneOfArray(v.meta?.roles, currentRoles)
);
newTree.forEach(
(v: any) => v.children && (v.children = filterNoPermissionTree(v.children))
);
return filterChildrenTree(newTree);
}
/** 批量删除缓存路由(keepalive) */
function delAliveRoutes(delAliveRouteList: Array<RouteConfigs>) {
delAliveRouteList.forEach(route => {
@@ -115,13 +152,13 @@ function addPathMatch() {
}
/** 初始化路由 */
function initRouter(name: string) {
function initRouter() {
return new Promise(resolve => {
getAsyncRoutes({ name }).then(({ info }) => {
if (info.length === 0) {
usePermissionStoreHook().changeSetting(info);
getAsyncRoutes().then(({ data }) => {
if (data.length === 0) {
usePermissionStoreHook().handleWholeMenus(data);
} else {
formatFlatteningRoutes(addAsyncRoutes(info)).map(
formatFlatteningRoutes(addAsyncRoutes(data)).map(
(v: RouteRecordRaw) => {
// 防止重复添加路由
if (
@@ -144,7 +181,7 @@ function initRouter(name: string) {
resolve(router);
}
);
usePermissionStoreHook().changeSetting(info);
usePermissionStoreHook().handleWholeMenus(data);
}
addPathMatch();
});
@@ -275,30 +312,29 @@ function getHistoryMode(): RouterHistory {
}
}
/** 是否有权限 */
function hasPermissions(value: Array<string>): boolean {
if (value && value instanceof Array && value.length > 0) {
const roles = usePermissionStoreHook().buttonAuth;
const permissionRoles = value;
/** 获取当前页面按钮级别的权限 */
function getAuths(): Array<string> {
return router.currentRoute.value.meta.auths as Array<string>;
}
const hasPermission = roles.some(role => {
return permissionRoles.includes(role);
});
if (!hasPermission) {
return false;
}
return true;
} else {
return false;
}
/** 是否有按钮级别的权限 */
function hasAuth(value: string | Array<string>): boolean {
if (!value) return false;
/** 从当前路由的`meta`字段里获取按钮级别的所有自定义`code`值 */
const metaAuths = getAuths();
const isAuths = isString(value)
? metaAuths.includes(value)
: isIncludeAllChildren(value, metaAuths);
return isAuths ? true : false;
}
export {
hasAuth,
getAuths,
ascending,
filterTree,
initRouter,
hasPermissions,
isOneOfArray,
getHistoryMode,
addAsyncRoutes,
delAliveRoutes,
@@ -306,5 +342,6 @@ export {
findRouteByPath,
handleAliveRoute,
formatTwoStageRoutes,
formatFlatteningRoutes
formatFlatteningRoutes,
filterNoPermissionTree
};