在 Vue 3 + Quasar + TypeScript 项目中实现 Navigation Guard 时出错

问题描述 投票:0回答:1

我正在使用 Quasar Framework 以及 Vue 3(利用带有语法的 Composition API)和 TypeScript 开发一个应用程序。我尝试在routes.ts文件中实现Navigation Guard来处理路由身份验证,但遇到以下错误:

ERROR in src/router/index.ts:26:5
TS2740: Type 'Router' is missing the following properties from type 'readonly RouteRecordRaw[]': length, concat, join, slice, and 16 more.
    24 |   const Router = createRouter({
    25 |     scrollBehavior: () => ({ left: 0, top: 0 }),
  > 26 |     routes,
       |     ^^^^^^
    27 |
    28 |     // Leave this as is and make changes in quasar.conf.js instead!
    29 |     // quasar.conf.js -> build -> vueRouterMode

这是我迄今为止尝试过的:

  1. 我最初按照标准 Vue 3 文档设置了 Navigation Guard。 遇到错误后,我尝试将 quasar.config.js 文件的 vueRouterMode 修改为“history”而不是“hash”,如某些论坛中的建议。
  2. 我还验证了所有依赖项均已更新并检查代码中是否有任何拼写错误或错误配置。
  3. 尽管做出了这些努力,错误仍然没有改变。我预计更新 vueRouterMode 或验证代码是否有错误可以解决该错误,但它仍然存在。

路线.ts

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import { useAuthStore } from 'src/stores/auth-store'; // Ensure you import your auth store
import MainLayout from 'layouts/MainLayout.vue';
import AdminLayout from 'layouts/AdminLayout.vue';
import IndexPage from 'pages/IndexPage.vue';
import SignUp from 'pages/Authentication/SignUp.vue';
import SignIn from 'pages/Authentication/SignIn.vue';
import DashboardPage from 'pages/SuperAdmin/DashboardPage.vue';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    component: MainLayout,
    children: [
      { path: '', component: SignUp },
      { path: '/home', component: IndexPage },
      { path: '/login', component: SignIn }
    ],
  },
  {
    path: '/admin',
    component: AdminLayout,
    children: [
      { path: '', component: DashboardPage },
    ],
    meta: { requiresAdmin: true }
  },
  {
    path: '/:catchAll(.*)*',
    component: () => import('pages/ErrorNotFound.vue'),
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,  // This is correct
});

router.beforeEach((to, from, next) => {
  const auth = useAuthStore();

  if (to.matched.some(record => record.meta.requiresAdmin)) {
    if (auth.isAdminUser) {
      next();
    } else {
      next('/');
    }
  } else {
    next();
  }
});

export default router;

auth-store.ts

import { defineStore } from 'pinia';
import AuthRequests from 'boot/api/AuthRequests';
import jwt_decode from 'jwt-decode';
import { api } from 'boot/axios';
import { Roles } from 'src/utils/Constants'


interface AuthState {
  jwt: string | null;
  expiration: number | null;
}

interface DecodedJWT {
  permissions?: string[];
  exp: number;
}

export const useAuthStore = defineStore('auth', {
  state: (): AuthState => {
    return JSON.parse(localStorage.getItem('authStore') as string) || {
      jwt: null,
      expiration: null
    };
  },
  getters: {
    isAuthenticated: (state: AuthState): boolean => {
      return state.jwt !== null;
    },
    hasPermission: (state: AuthState) => (permission: string): boolean => {
      if (!state.jwt) return false;
      const decoded_jwt: DecodedJWT = jwt_decode(state.jwt);
      return decoded_jwt.permissions ? decoded_jwt.permissions.includes(permission) : false;
    },
    isAdminUser: (): boolean => useAuthStore().hasPermission(Roles.ADMIN),
    isVenueOwner: (): boolean => useAuthStore().hasPermission(Roles.VENUE_OWNER),
    isStaff: (): boolean => useAuthStore().hasPermission(Roles.STAFF),
    isEventOrganizer: (): boolean => useAuthStore().hasPermission(Roles.EVENT_ORGANIZER),
    isGroupAdmin: (): boolean => useAuthStore().hasPermission(Roles.GROUP_ADMIN),
    isStandardUser: (): boolean => useAuthStore().hasPermission(Roles.USER),
  },
  actions: {
    async authenticate(email: string, password: string): Promise<void> {
      try {
        const { data } = await AuthRequests.authenticate(email, password);
        const decoded_jwt: DecodedJWT = jwt_decode(data);

        this.jwt = data;
        this.expiration = decoded_jwt.exp;
        api.defaults.headers.common['Authorization'] = 'Bearer ' + data;

        localStorage.setItem('authStore', JSON.stringify({
          jwt: data,
          expiration: decoded_jwt.exp,
        }));
      } catch (e) {
        console.error(e);
      }
    },
    logout(): void {
      this.jwt = null;
      delete api.defaults.headers.common['Authorization'];
      localStorage.removeItem('authStore');
    }
  }
});

src/路由器/index.ts

import { route } from 'quasar/wrappers';
import {
  createMemoryHistory,
  createRouter,
  createWebHashHistory,
  createWebHistory,
} from 'vue-router';
import routes from './routes';

export default route(function (/* { store, ssrContext } */) {
  const createHistory = process.env.SERVER
    ? createMemoryHistory
    : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);

  const Router = createRouter({
    scrollBehavior: () => ({ left: 0, top: 0 }),
    routes,

    history: createHistory(
      process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE
    ),
  });

  return Router;
});
typescript vuejs3 vue-router vue-composition-api quasar-framework
1个回答
0
投票

似乎您创建了两次路由器,一次在index.ts中,一次在routes.ts中。我建议将创建内容保留在 index.ts 内,并在那里添加防护。基本上将其从

routes.ts
中删除并仅导出
routes
:

const router = createRouter({
  history: createWebHistory(),
  routes,  // This is correct
});

router.beforeEach((to, from, next) => {
  const auth = useAuthStore();

  if (to.matched.some(record => record.meta.requiresAdmin)) {
    if (auth.isAdminUser) {
      next();
    } else {
      next('/');
    }
  } else {
    next();
  }
});

并将其添加到

index.ts
:

export default route(function (/* { store, ssrContext } */) {
  const createHistory = process.env.SERVER
    ? createMemoryHistory
    : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);

  const Router = createRouter({
    scrollBehavior: () => ({ left: 0, top: 0 }),
    routes,

    history: createHistory(
      process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE
    ),
  });

  Router.beforeEach((to, from, next) => {
    const auth = useAuthStore();

    if (to.matched.some(record => record.meta.requiresAdmin)) {
      if (auth.isAdminUser) {
        next();
      } else {
        next('/');
      }
    } else {
      next();
    }
  });

  return Router;
});
© www.soinside.com 2019 - 2024. All rights reserved.