vue3封装路由守卫(白名单,权限,token校验)封装思路

28 阅读1分钟

image.png

import PageLayout from '@/layout/page-layout.vue';
import 'nprogress/nprogress.css';
import { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router';
import { setupRouterGuard } from './guard';
import appRoutes from './modules';
import BindPhone from './modules/bindPhone';
import ForgetPassword from './modules/forget-password';
import Login from './modules/login';
import LoginSuccess from './modules/login-success';
 
 
 
const routes: RouteRecordRaw[] = [
  {
    path: '/',
    redirect: 'login',
  },
  Login,
  ForgetPassword,
  LoginSuccess,
  BindPhone,
  {
    name: 'root',
    path: '/',
    component: PageLayout,
    children: appRoutes,
  },
  {
    path: '/:pathMatch(.*)*',
    name: 'notFound',
    component: () => import('@/views/not-found/index.vue'),
  },
]
 
const router = createRouter({
  history: createWebHashHistory(''),
  routes,
  scrollBehavior() {
    return { top: 0 }
  },
})
 
 
setupRouterGuard(router)
 
export default router
// src/router/guard/index.ts
 
import NProgress from 'nprogress'
import type { Router } from 'vue-router'
import { setupPermissionGuard } from './permission'
import { setupTokenGuard } from './token'
import { setupWhiteListGuard } from './whiteList'
 
export function setupRouterGuard(router: Router) {
  router.beforeEach(async (to, from, next) => {
    NProgress.start()
 
    const guards = [setupWhiteListGuard, setupTokenGuard, setupPermissionGuard]
 
    try {
      const results = await Promise.all(
        guards.map(guard => guard(to, from, next))
      )
 
      if (results.includes(false)) {
        return
      }
 
      next()
    } catch (error) {
      console.error('Router guard error:', error)
      next('/login')
    }
  })
 
  router.afterEach(() => {
    NProgress.done()
  })
}
// src/router/guard/permission.ts
import usePermission from '@/hooks/permission';
import { useUserStore } from '@/store';
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
import { LocationQueryRaw } from 'vue-router';
import appRoutes from '../modules';
 
// 路由权限判断
async function crossroads(
  to: RouteLocationNormalized,
  next: NavigationGuardNext,
  userStore: any
) {
  const Permission = usePermission()
  if (Permission.accessRouter(to)) {
    await next()
  } else {
    const destination = Permission.findFirstPermissionRoute(appRoutes, userStore.role) || {
      name: 'notFound'
    }
    await next(destination)
  }
}
 
export async function setupPermissionGuard(
  to: RouteLocationNormalized,
  _: RouteLocationNormalized,
  next: NavigationGuardNext
) {
  const userStore = useUserStore()
 
  if (userStore.role) {
    await crossroads(to, next, userStore)
  } else {
    try {
      // await userStore.info()
      await crossroads(to, next, userStore)
    } catch (error) {
      next({
        name: 'login',
        query: {
          redirect: to.name,
          ...to.query,
        } as LocationQueryRaw,
      })
    }
  }
  return false
}
// src/router/guard/token.ts
import { getToken } from '@/utils/auth'
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
 
export function setupTokenGuard(
  to: RouteLocationNormalized,
  _: RouteLocationNormalized,
  next: NavigationGuardNext
) {
  const token = getToken()
  if (!token) {
    next({
      name: 'login',
      query: { redirect: to.fullPath }
    })
    return false
  }
  return true
}
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
 
const whiteList = ['login', 'register', 'forget-password']
 
export function setupWhiteListGuard(
  to: RouteLocationNormalized,
  _: RouteLocationNormalized,
  next: NavigationGuardNext
) {
  if (whiteList.includes(to.name as string)) {
    next()
    return false
  }
  return true
}