guard.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import type { Router } from 'vue-router';
  2. import { LOGIN_PATH } from '@vben/constants';
  3. import { preferences } from '@vben/preferences';
  4. import { useAccessStore, useUserStore } from '@vben/stores';
  5. import { startProgress, stopProgress } from '@vben/utils';
  6. import { accessRoutes, coreRouteNames } from '#/router/routes';
  7. import { useAuthStore } from '#/store';
  8. import { generateAccess } from './access';
  9. /**
  10. * 通用守卫配置
  11. * @param router
  12. */
  13. function setupCommonGuard(router: Router) {
  14. // 记录已经加载的页面
  15. const loadedPaths = new Set<string>();
  16. router.beforeEach((to) => {
  17. to.meta.loaded = loadedPaths.has(to.path);
  18. // 页面加载进度条
  19. if (!to.meta.loaded && preferences.transition.progress) {
  20. startProgress();
  21. }
  22. return true;
  23. });
  24. router.afterEach((to) => {
  25. // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
  26. loadedPaths.add(to.path);
  27. // 关闭页面加载进度条
  28. if (preferences.transition.progress) {
  29. stopProgress();
  30. }
  31. });
  32. }
  33. /**
  34. * 权限访问守卫配置
  35. * @param router
  36. */
  37. function setupAccessGuard(router: Router) {
  38. router.beforeEach(async (to, from) => {
  39. const accessStore = useAccessStore();
  40. const userStore = useUserStore();
  41. const authStore = useAuthStore();
  42. // 基本路由,这些路由不需要进入权限拦截
  43. if (coreRouteNames.includes(to.name as string)) {
  44. if (to.path === LOGIN_PATH && accessStore.accessToken) {
  45. return decodeURIComponent(
  46. (to.query?.redirect as string) ||
  47. userStore.userInfo?.homePath ||
  48. preferences.app.defaultHomePath,
  49. );
  50. }
  51. return true;
  52. }
  53. // accessToken 检查
  54. if (!accessStore.accessToken) {
  55. // 明确声明忽略权限访问权限,则可以访问
  56. if (to.meta.ignoreAccess) {
  57. return true;
  58. }
  59. // 没有访问权限,跳转登录页面
  60. if (to.fullPath !== LOGIN_PATH) {
  61. return {
  62. path: LOGIN_PATH,
  63. // 如不需要,直接删除 query
  64. query:
  65. to.fullPath === preferences.app.defaultHomePath
  66. ? {}
  67. : { redirect: encodeURIComponent(to.fullPath) },
  68. // 携带当前跳转的页面,登录后重新跳转该页面
  69. replace: true,
  70. };
  71. }
  72. return to;
  73. }
  74. // 是否已经生成过动态路由
  75. if (accessStore.isAccessChecked) {
  76. return true;
  77. }
  78. // 生成路由表
  79. // 当前登录用户拥有的角色标识列表
  80. const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
  81. const userRoles = userInfo.roles ?? [];
  82. // 生成菜单和路由
  83. const { accessibleMenus, accessibleRoutes } = await generateAccess({
  84. roles: userRoles,
  85. router,
  86. // 则会在菜单中显示,但是访问会被重定向到403
  87. routes: accessRoutes,
  88. });
  89. // 保存菜单信息和路由信息
  90. accessStore.setAccessMenus(accessibleMenus);
  91. accessStore.setAccessRoutes(accessibleRoutes);
  92. accessStore.setIsAccessChecked(true);
  93. let redirectPath: string;
  94. if (from.query.redirect) {
  95. redirectPath = from.query.redirect as string;
  96. } else if (to.path === preferences.app.defaultHomePath) {
  97. redirectPath = preferences.app.defaultHomePath;
  98. } else if (userInfo.homePath && to.path === userInfo.homePath) {
  99. redirectPath = userInfo.homePath;
  100. } else {
  101. redirectPath = to.fullPath;
  102. }
  103. return {
  104. ...router.resolve(decodeURIComponent(redirectPath)),
  105. replace: true,
  106. };
  107. });
  108. }
  109. /**
  110. * 项目守卫配置
  111. * @param router
  112. */
  113. function createRouterGuard(router: Router) {
  114. /** 通用 */
  115. setupCommonGuard(router);
  116. /** 权限访问 */
  117. setupAccessGuard(router);
  118. }
  119. export { createRouterGuard };