mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-19 19:42:26 +08:00
fix: enforce permission-aware navigation
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { useGlobalSettingsStore } from '@/stores'
|
||||
import type { NavMenuTabItem } from '@/@layouts/types'
|
||||
import type { NavMenu, NavMenuTabItem } from '@/@layouts/types'
|
||||
import type { Composer } from 'vue-i18n'
|
||||
|
||||
// 构建路由菜单,每次调用时使用当前的语言环境
|
||||
export function getNavMenus(t: Composer['t']) {
|
||||
export function getNavMenus(t: Composer['t']): NavMenu[] {
|
||||
const globalSettingsStore = useGlobalSettingsStore()
|
||||
|
||||
// 检查是否为高级模式
|
||||
@@ -17,7 +17,7 @@ export function getNavMenus(t: Composer['t']) {
|
||||
header: t('menu.start'),
|
||||
admin: false,
|
||||
footer: true,
|
||||
permission: 'manage',
|
||||
permission: 'admin',
|
||||
},
|
||||
{
|
||||
title: t('navItems.searchResult'),
|
||||
@@ -119,7 +119,7 @@ export function getNavMenus(t: Composer['t']) {
|
||||
to: '/plugins',
|
||||
header: t('menu.system'),
|
||||
admin: true,
|
||||
permission: 'manage',
|
||||
permission: 'admin',
|
||||
tabs: getPluginTabs(t),
|
||||
},
|
||||
{
|
||||
@@ -148,7 +148,7 @@ export function getNavMenus(t: Composer['t']) {
|
||||
admin: true,
|
||||
permission: 'admin',
|
||||
tabs: getSettingTabs(t),
|
||||
},
|
||||
} as NavMenu,
|
||||
]
|
||||
: []),
|
||||
]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import { configureNProgress } from '@/api/nprogress'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import { useAuthStore, usePluginSidebarNavStore, useUserStore } from '@/stores'
|
||||
import { setNavigatingState as setRequestNavigatingState } from '@/utils/requestOptimizer'
|
||||
import { buildUserPermissionContext, hasPermission, type UserPermissionKey } from '@/utils/permission'
|
||||
|
||||
// Nprogress
|
||||
configureNProgress()
|
||||
@@ -15,7 +16,15 @@ const router = createRouter({
|
||||
return { top: 0 }
|
||||
},
|
||||
routes: [
|
||||
{ path: '/', redirect: '/dashboard' },
|
||||
{
|
||||
path: '/',
|
||||
redirect: () => {
|
||||
const authStore = useAuthStore()
|
||||
const userStore = useUserStore()
|
||||
if (!authStore.token) return '/login'
|
||||
return userStore.superUser ? '/dashboard' : '/apps'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('../layouts/default.vue'),
|
||||
@@ -26,6 +35,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -34,6 +44,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'discovery',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -42,6 +53,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'discovery',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -50,6 +62,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'search',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -59,6 +72,7 @@ const router = createRouter({
|
||||
keepAlive: true,
|
||||
keepAliveKey: 'subscribe-movie',
|
||||
requiresAuth: true,
|
||||
permission: 'subscribe',
|
||||
subType: '电影',
|
||||
},
|
||||
},
|
||||
@@ -69,6 +83,7 @@ const router = createRouter({
|
||||
keepAlive: true,
|
||||
keepAliveKey: 'subscribe-tv',
|
||||
requiresAuth: true,
|
||||
permission: 'subscribe',
|
||||
subType: '电视剧',
|
||||
},
|
||||
},
|
||||
@@ -77,6 +92,7 @@ const router = createRouter({
|
||||
component: () => import('../pages/subscribe-share.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
permission: 'subscribe',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -85,6 +101,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'manage',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -93,6 +110,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'subscribe',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -101,6 +119,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'manage',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -109,6 +128,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'manage',
|
||||
hideFooter: true,
|
||||
},
|
||||
},
|
||||
@@ -118,6 +138,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'manage',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -126,6 +147,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -142,6 +164,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -158,6 +181,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -166,6 +190,7 @@ const router = createRouter({
|
||||
props: true,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
permission: 'discovery',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -189,6 +214,7 @@ const router = createRouter({
|
||||
component: () => import('../pages/media.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
permission: 'discovery',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -197,6 +223,7 @@ const router = createRouter({
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
requiresAuth: true,
|
||||
permission: 'manage',
|
||||
hideFooter: true,
|
||||
},
|
||||
},
|
||||
@@ -223,6 +250,7 @@ const router = createRouter({
|
||||
component: () => import('../pages/setup.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
permission: 'admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -234,6 +262,24 @@ const router = createRouter({
|
||||
],
|
||||
})
|
||||
|
||||
async function getRoutePermission(to: any): Promise<UserPermissionKey | undefined> {
|
||||
if (to.meta.permission) {
|
||||
return to.meta.permission as UserPermissionKey
|
||||
}
|
||||
|
||||
if (to.name !== 'plugin-app') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const pluginId = String(to.params.pluginId || '')
|
||||
const navKey = String(to.params.navKey || 'main')
|
||||
const pluginSidebarNavStore = usePluginSidebarNavStore()
|
||||
await pluginSidebarNavStore.ensureSidebarNav()
|
||||
|
||||
const navItem = pluginSidebarNavStore.items.find(item => item.plugin_id === pluginId && item.nav_key === navKey)
|
||||
return (navItem?.permission || undefined) as UserPermissionKey | undefined
|
||||
}
|
||||
|
||||
// 路由导航守卫
|
||||
router.beforeEach(async (to: any, from: any, next: any) => {
|
||||
// 设置导航状态 - 同时中断API请求
|
||||
@@ -249,6 +295,24 @@ router.beforeEach(async (to: any, from: any, next: any) => {
|
||||
// 用户未登录,重定向到登录页
|
||||
setRequestNavigatingState(false)
|
||||
next('/login')
|
||||
} else if (to.meta.requiresAuth) {
|
||||
const routePermission = await getRoutePermission(to)
|
||||
if (!routePermission) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const allowed = hasPermission(
|
||||
buildUserPermissionContext(userStore.superUser, userStore.permissions),
|
||||
routePermission,
|
||||
)
|
||||
if (!allowed) {
|
||||
setRequestNavigatingState(false)
|
||||
next('/apps')
|
||||
return
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user