From 157a8eb42d8faea30ea5e0e51bdd7bec702b3a1d Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 19 Aug 2025 15:01:15 +0800 Subject: [PATCH] Support async route permissions in guards (#7700) #### What type of PR is this? /area ui /kind bug /milestone 2.21.x #### What this PR does / why we need it: Fix routing navigation issue with async route permission functions Caused by https://github.com/halo-dev/halo/pull/7688 #### Does this PR introduce a user-facing change? ```release-note None ``` --- ui/console-src/router/guards/permission.ts | 36 +++++++++++----- ui/uc-src/router/guards/permission.ts | 48 ++++++++++++++++------ 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/ui/console-src/router/guards/permission.ts b/ui/console-src/router/guards/permission.ts index ba6b97241..0e5fcf9a6 100644 --- a/ui/console-src/router/guards/permission.ts +++ b/ui/console-src/router/guards/permission.ts @@ -7,7 +7,7 @@ import type { Role } from "@halo-dev/api-client"; import type { RouteLocationNormalized, Router } from "vue-router"; export function setupPermissionGuard(router: Router) { - router.beforeEach((to, _, next) => { + router.beforeEach(async (to, _, next) => { const userStore = useUserStore(); const roleStore = useRoleStore(); @@ -16,7 +16,7 @@ export function setupPermissionGuard(router: Router) { return; } - if (checkRoutePermissions(to, roleStore.permissions.uiPermissions)) { + if (await checkRoutePermissions(to, roleStore.permissions.uiPermissions)) { next(); } else { next({ name: "Forbidden" }); @@ -38,17 +38,31 @@ function isConsoleAccessDisallowed(currentRoles?: Role[]): boolean { ); } -function checkRoutePermissions( +async function checkRoutePermissions( to: RouteLocationNormalized, uiPermissions: string[] -): boolean { +): Promise { const { meta } = to; - if (meta?.permissions) { - return hasPermission( - Array.from(uiPermissions), - meta.permissions as string[], - true - ); + + if (!meta?.permissions) { + return true; } - return true; + + if (typeof meta.permissions === "function") { + try { + return await meta.permissions(uiPermissions); + } catch (e) { + console.error( + `Error checking permissions for route ${String(to.name)}:`, + e + ); + return false; + } + } + + return hasPermission( + Array.from(uiPermissions), + meta.permissions as string[], + true + ); } diff --git a/ui/uc-src/router/guards/permission.ts b/ui/uc-src/router/guards/permission.ts index 5eac94bdb..fdce3bee3 100644 --- a/ui/uc-src/router/guards/permission.ts +++ b/ui/uc-src/router/guards/permission.ts @@ -1,22 +1,44 @@ import { useRoleStore } from "@/stores/role"; import { hasPermission } from "@/utils/permission"; -import type { Router } from "vue-router"; +import type { RouteLocationNormalized, Router } from "vue-router"; export function setupPermissionGuard(router: Router) { - router.beforeEach((to, _from, next) => { + router.beforeEach(async (to, _from, next) => { const roleStore = useRoleStore(); const { uiPermissions } = roleStore.permissions; - const { meta } = to; - if (meta && meta.permissions) { - const flag = hasPermission( - Array.from(uiPermissions), - meta.permissions as string[], - true - ); - if (!flag) { - next({ name: "Forbidden" }); - } + if (await checkRoutePermissions(to, uiPermissions)) { + next(); + } else { + next({ name: "Forbidden" }); } - next(); }); } + +async function checkRoutePermissions( + to: RouteLocationNormalized, + uiPermissions: string[] +): Promise { + const { meta } = to; + + if (!meta?.permissions) { + return true; + } + + if (typeof meta.permissions === "function") { + try { + return await meta.permissions(uiPermissions); + } catch (e) { + console.error( + `Error checking permissions for route ${String(to.name)}:`, + e + ); + return false; + } + } + + return hasPermission( + Array.from(uiPermissions), + meta.permissions as string[], + true + ); +}