实现思路
技术实现
VUE3
路由入口
路径:@/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
//静态路由表
import { static_router } from './utils/static_router'
//动态路由表
import { dynamic_router } from './utils/dynamic_router'
//白名单
import { Whitelist } from './utils/white_list'
import { useUserInfo } from "@/stores/user";
import { routerFilter } from './utils/router_filter';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: static_router
})
router.beforeEach((to, from, next) => {
const userInfoStore = useUserInfo();
const token = userInfoStore.token
const role = userInfoStore.userInfo.role
if (token) {
if (!userInfoStore.final_dyn_router.length) {
userInfoStore.setFinalDYNRouter(routerFilter(role, dynamic_router))
userInfoStore.final_dyn_router.forEach((route) => {
router.addRoute(route)
})
router.addRoute({ path: "/:pathMatch(.*)*",name:"redirect", redirect: "/404",meta: { isDyn: true } })
console.log(router.getRoutes())
next({ ...to, replace: true })
} else {
next()
}
} else {
if (Whitelist.includes(to.path)) {
next()
} else {
next("/login")
}
}
})
export default router
动态路由
路径:@/router/utils/dynamic_router.js
//动态路由表
export const dynamic_router = [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: {
title: '仪表盘',
auth: true, // 需要登录
isDyn:true,
roles: ['admin', 'user', 'guest'] // 所有角色均可访问
}
},
{
path: '/user',
name: 'UserManage',
component: () => import('@/views/UserManage.vue'),
meta: {
title: '用户管理',
auth: true,
isDyn:true,
roles: ['admin'] // 仅管理员可访问
}
},
{
path: '/settings',
name: 'Settings',
component: () => import('@/views/Settings.vue'),
meta: {
title: '系统设置',
auth: true,
isDyn:true,
roles: ['admin', 'user'] // 管理员和普通用户可访问
}
},
{
path: '/profile',
name: 'Profile',
component: () => import('@/views/Profile.vue'),
meta: {
title: '个人资料',
auth: true,
isDyn:true,
roles: ['admin', 'user', 'guest'] // 所有登录用户可访问
}
},
{
path: '/guest-only',
name: 'GuestOnly',
component: () => import('@/views/GuestPage.vue'),
meta: {
title: '访客专区',
auth: true,
isDyn:true,
roles: ['guest'] // 仅 guest 角色可访问
}
}
]
静态路由
路径:@/router/utils/static_router.js
// 静态路由表
export const static_router = [
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue'),
meta: { title: '登录', auth: false } // 不需要权限
},
{
path: '/403',
name: 'Forbidden',
component: () => import('@/views/403.vue'),
meta: { title: '403', auth: false }
},
{
path: '/404',
name: 'NotFound',
component: () => import('@/views/404.vue'),
meta: { title: '404', auth: false }
},
{
path: '/',
redirect: '/dashboard', // 登录后默认跳转仪表盘,但本身是公开路由(无 token 时会被守卫拦截)
meta: { auth: false }
},
];
白名单
路径:@/router/utils/white_list.js
//白名单
export const Whitelist = [
'/login',
'/403',
'/404',
'/register', // 如果有注册页
'/forgot-password', // 如果有忘记密码页
'/', // 根路径(通常重定向到仪表盘,但无 token 时会被守卫拦截,建议也加入白名单,守卫中再根据具体逻辑处理)
];
重置路由函数
路径:@/router/utils/reset_router.js
//重置路由 删除所有的动态路由规则
export const resetRouter = (router)=>{
const routes = router.getRoutes()
routes.forEach((route)=>{
if(route.meta.isDyn){
router.removeRoute(route.name)
}
})
}
根据身份过滤动态路由
路径:@/router/utils/router_filter.js
//根据身份过滤动态路由
export function routerFilter(role,routes){
if(role&&routes){
routes = routes.filter((route)=>{
if(route.children){
route.children = routerFilter(role,route.children)
}
return route.meta.roles.includes(role)
})
}
return routes
}
设置用户状态管理
路径:@/sotres/user.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useUserInfo = defineStore('user', () => {
const userInfo = ref(JSON.parse(localStorage.getItem("userInfo"))||{})
const token = ref (localStorage.getItem("token")||"")
const final_dyn_router = ref([])
function setUserInfo(value){
localStorage.setItem("userInfo",JSON.stringify(value))
userInfo.value = value
}
function setToken(value){
localStorage.setItem("token",value)
token.value = value
}
function setFinalDYNRouter(value){
final_dyn_router.value =value
}
function removeUserInfo(){
localStorage.removeItem("userInfo")
userInfo.value = {}
}
function removeToken(){
localStorage.removeItem("token")
token.value = ""
}
function removeFinalDYNRouter(){
final_dyn_router.value = []
}
return {
setUserInfo,
setToken,
setFinalDYNRouter,
userInfo,
token,
final_dyn_router,
removeUserInfo,
removeToken,
removeFinalDYNRouter
}
})
根组件
路径:@/App.vue
<template>
<div>
<button @click="loginout">退出登录</button>
</div>
<router-view></router-view>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { useUserInfo } from './stores/user';
import { resetRouter } from './router/utils/reset_router';
const userInfoStore = useUserInfo()
const router = useRouter()
function loginout(){
resetRouter(router)
userInfoStore.removeFinalDYNRouter()
userInfoStore.removeToken()
userInfoStore.removeUserInfo()
router.replace({path:"/login"})
}
</script>
<style>
</style>