Vue3-权限管理

976 阅读2分钟

Vue3权限管理,实现侧边栏的渲染以及路由权限拦截。

1.侧边栏渲染

index.vue 侧边栏

<el-scrollbar>
	<el-menu
	:default-active="activeMenu"
	:router="true"
	:collapse="isCollapse"
	:collapse-transition="false"
	:unique-opened="true"
	background-color="#191a20"
        text-color="#bdbdc0"
	active-text-color="#fff"
	>
         <SubItem :menuList="menuList"></SubItem> //列表渲染
   </el-menu>
</el-scrollbar>

<script setup lang="ts">

//后台数据获取,存储到pinia
onMounted(async () => {
	loading.value = true;
	try {
		const { data } = await getMenuList();
		console.log(data);
		// 将路由信息存储到pinia中
		menuStore.setMenuList(data as Menu.MenuOptions[]);
	} finally {
		// 关闭加载
		loading.value = false;
	}
});

//从pinia中读取数据
const menuList = computed((): Menu.MenuOptions[] => menuStore.menuList);

</script>

menu.ts 侧边栏数据Pinia

import { defineStore } from "pinia";
import { MenuState } from "../interface";
import piniaPersistConfig from "@/config/piniaPersist"; //数据持久化

// MenuStore
export const MenuStore = defineStore({
	id: "MenuState",
	state: (): MenuState => ({
		// menu collapse
		isCollapse: false,
		// menu List
		menuList: []  //数据列表
	}),
	getters: {},
	actions: {
		async setCollapse() {
			this.isCollapse = !this.isCollapse;
		},
                //数据存储,并持久化,全局都能使用
		async setMenuList(menuList: Menu.MenuOptions[]) {
			this.menuList = menuList;
		}
	},
        //持久化
	persist: piniaPersistConfig("MenuState")
});

2.路由权限(在侧边栏渲染的基础上)

index.vue 侧边栏

<script setup lang="ts">

//后台数据获取,存储到pinia
onMounted(async () => {
	loading.value = true;
	try {
	const { data } = await getMenuList();
		// 将data处理成一维数组,存储到 pinia 中
		const dynamicRouter = handleRouter(data as Menu.MenuOptions[]);//处理函数在最后
		authStore.setAuthRouter(dynamicRouter);
		// 将路由信息存储到pinia中
		menuStore.setMenuList(data as Menu.MenuOptions[]);
	} finally {
		// 关闭加载
		loading.value = false;
	}
});

//从pinia中读取数据
const menuList = computed((): Menu.MenuOptions[] => menuStore.menuList);

</script>

auth.ts 权限路由Pinia

import { defineStore } from "pinia";
import { AuthState } from "../interface";
import piniaPersistConfig from "@/config/piniaPersist";

// AuthStore
export const AuthStore = defineStore({
	id: "AuthState",
	state: (): AuthState => ({
		// 用户按钮权限列表
		authButtons: {},
		// 路由权限列表
		authRouter: []
	}),
	getters: {
		// 处理权限按钮数据,用于方便控制按钮
		authButtonsObj: state => {
			return state.authButtons;
		},
		// 后台返回的菜单数据,用于方便控制路由跳转时权限(这里已经处理成一维数组了)
		dynamicRouter: state => {
			return state.authRouter;
		}
	},
	actions: {
		// setAuthButtons  处理权限按钮
		async setAuthButtons(authButtonList: { [key: string]: any }) {
			this.authButtons = authButtonList;
		},
		// setAuthRouter 处理权限路由
		async setAuthRouter(dynamicRouter: string[]) {
			this.authRouter = dynamicRouter;
		}
	},
	persist: piniaPersistConfig("AuthState")
});

index.ts 路由守卫

···
import { AuthStore } from "@/store/modules/auth";
import { GlobalStore } from "@/store";
import { AxiosCanceler } from "@/api/helper/axiosCancel";

// 路由前置拦截器
router.beforeEach((to, from, next) => {
	NProgress.start();
	// 清除之前的所有请求
	const axiosCanceler = new AxiosCanceler();
	axiosCanceler.removeAllPending();
	// 判断当前路由是否需要权限
	if (to.matched.some(record => record.meta.requiresAuth)) {
		console.log(to);

		return next();
	}
	// if (!to.meta.requiresAuth) {
	// 	console.log(to);

	// 	return next();
	// }
	// * 判断是否有Token
	const globalStore = GlobalStore();
	if (!globalStore.token) {
		next({
			path: "/login"
		});
		NProgress.done();
		return;
	}
	// 判断to的路由是否在当前角色的路由表中
	const authStore = AuthStore();

	// * Dynamic Router(动态路由,根据后端返回的菜单数据生成的一维数组)
	const dynamicRouter = authStore.dynamicRouter;
	const staticRouter = [HOME_URL, "/403"];
	const routerList = dynamicRouter.concat(staticRouter);
	// * 如果访问的地址没有在路由表中重定向到403页面
	if (routerList.indexOf(to.path) !== -1) return next();
	next({
		path: "/403"
	});
});
router.afterEach(() => {
	NProgress.done();
});

export default router;

数组处理
/**
 * 使用递归处理路由菜单
 * @param newArr 所有菜单数组
 */
export function handleRouter(routerList: Menu.MenuOptions[], newArr: string[] = []) {
	routerList.forEach((item: Menu.MenuOptions) => {
		typeof item === "object" && item.path && newArr.push(item.path);
		item.children && item.children.length && handleRouter(item.children, newArr);
	});
	return newArr;
}