Ben Lin
2024-06-12 da85b09c600ddcf4e5c8cad66012fa29a8252b39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import type { Router, RouteRecordRaw } from 'vue-router';
 
import { usePermissionStoreWithOut } from '/@/store/modules/permission';
 
import { PageEnum } from '/@/enums/pageEnum';
import { useUserStoreWithOut } from '/@/store/modules/user';
 
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
 
import { RootRoute } from '/@/router/routes';
import { isEmpty, isNullOrUnDef } from '/@/utils/is';
 
const LOGIN_PATH = PageEnum.BASE_LOGIN;
 
const ROOT_PATH = RootRoute.path;
 
const whitePathList: PageEnum[] = [LOGIN_PATH];
 
export function createPermissionGuard(router: Router) {
  const userStore = useUserStoreWithOut();
  const permissionStore = usePermissionStoreWithOut();
  router.beforeEach(async (to, from, next) => {
    if (
      from.path === ROOT_PATH &&
      to.path === PageEnum.BASE_HOME &&
      userStore.getUserInfo.homePath &&
      userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
    ) {
      next(userStore.getUserInfo.homePath);
      return;
    }
 
    const token = userStore.getToken;
 
    // Whitelist can be directly entered
    if (whitePathList.includes(to.path as PageEnum)) {
      if (to.path === LOGIN_PATH && token) {
        const isSessionTimeout = userStore.getSessionTimeout;
        try {
          await userStore.afterLoginAction();
          if (!isSessionTimeout) {
            next((to.query?.redirect as string) || '/');
            return;
          }
        } catch {
          //
        }
      }
      next();
      return;
    }
    // token or user does not exist
    if (!token) {
      // You can access without permission. You need to set the routing meta.ignoreAuth to true
      if (to.meta.ignoreAuth) {
        next();
        return;
      }
 
      // redirect login page
      const redirectData: { path: string; replace: boolean; query?: Recordable<string> } = {
        path: LOGIN_PATH,
        replace: true,
      };
      if (to.path) {
        redirectData.query = {
          ...redirectData.query,
          redirect: to.path,
        };
      }
      next(redirectData);
      return;
    }
 
    // Jump to the 404 page after processing the login
    if (
      from.path === LOGIN_PATH &&
      to.name === PAGE_NOT_FOUND_ROUTE.name &&
      to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)
    ) {
      next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
      return;
    }
 
    // get userinfo while last fetch time is empty
    if (userStore.getLastUpdateTime === 0) {
      try {
        const userinfo = await userStore.getUserInfoAction();
 
        if (isNullOrUnDef(userinfo?.userId)) {
          userStore.setToken(undefined);
          userStore.setSessionTimeout(false);
          userStore.setUserInfo(null);
          next(PageEnum.BASE_LOGIN);
          return;
        }
      } catch (err) {
        next();
        return;
      }
    }
 
    if (permissionStore.getIsDynamicAddedRoute) {
      next();
      return;
    }
 
    const routes = await permissionStore.buildRoutesAction();
 
    routes.forEach((route) => {
      router.addRoute(route as unknown as RouteRecordRaw);
    });
 
    router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
 
    permissionStore.setDynamicAddedRoute(true);
 
    if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
      // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容
      next({ path: to.fullPath, replace: true, query: to.query });
    } else {
      const redirectPath = (from.query.redirect || to.path) as string;
      const redirect = decodeURIComponent(redirectPath);
      const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
      next(nextData);
    }
  });
}