feat(auth): enforce admin permissions in UI
Add can()/router meta, HomePage module filtering, Admins permission matrix, and hide write actions when the user lacks *:write. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import type { PermissionCode } from '@/auth/permissions'
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
public?: boolean
|
||||
permissions?: PermissionCode[]
|
||||
permissionMode?: 'all' | 'any'
|
||||
}
|
||||
}
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
@@ -23,81 +33,97 @@ const router = createRouter({
|
||||
path: 'sms',
|
||||
name: 'sms-panel',
|
||||
component: () => import('@/pages/SmsPanelPage.vue'),
|
||||
meta: { permissions: ['sms:read'] },
|
||||
},
|
||||
{
|
||||
path: 'sms/:tenantId',
|
||||
name: 'sms-tenant',
|
||||
component: () => import('@/pages/SmsTenantPage.vue'),
|
||||
meta: { permissions: ['sms:read'] },
|
||||
},
|
||||
{
|
||||
path: 'servers',
|
||||
name: 'server-panel',
|
||||
component: () => import('@/pages/ServerPanelPage.vue'),
|
||||
meta: { permissions: ['servers:read'] },
|
||||
},
|
||||
{
|
||||
path: 'servers/:tenantId',
|
||||
name: 'server-tenant',
|
||||
component: () => import('@/pages/ServerTenantPage.vue'),
|
||||
meta: { permissions: ['servers:read'] },
|
||||
},
|
||||
{
|
||||
path: 'plugins',
|
||||
name: 'plugin-panel',
|
||||
component: () => import('@/pages/PluginPanelPage.vue'),
|
||||
meta: { permissions: ['plugins:read'] },
|
||||
},
|
||||
{
|
||||
path: 'plugins/:tenantId',
|
||||
name: 'plugin-tenant',
|
||||
component: () => import('@/pages/PluginTenantPage.vue'),
|
||||
meta: { permissions: ['plugins:read'] },
|
||||
},
|
||||
{
|
||||
path: 'support',
|
||||
name: 'support-panel',
|
||||
component: () => import('@/pages/SupportPanelPage.vue'),
|
||||
meta: { permissions: ['support:read'] },
|
||||
},
|
||||
{
|
||||
path: 'support/:tenantId',
|
||||
name: 'support-tenant',
|
||||
component: () => import('@/pages/SupportTenantPage.vue'),
|
||||
meta: { permissions: ['support:read'] },
|
||||
},
|
||||
{
|
||||
path: 'admins',
|
||||
name: 'admins',
|
||||
component: () => import('@/pages/AdminsPage.vue'),
|
||||
meta: { permissions: ['admins:read'] },
|
||||
},
|
||||
{
|
||||
path: 'products/:product',
|
||||
name: 'product-versions',
|
||||
component: () => import('@/pages/ProductVersionsPage.vue'),
|
||||
meta: { permissions: ['hamkar:read', 'khanegi:read'], permissionMode: 'any' },
|
||||
},
|
||||
{
|
||||
path: 'versions/new',
|
||||
name: 'version-create',
|
||||
component: () => import('@/pages/TenantFormPage.vue'),
|
||||
meta: { permissions: ['hamkar:write', 'khanegi:write'], permissionMode: 'any' },
|
||||
},
|
||||
{
|
||||
path: 'versions/:id',
|
||||
name: 'version-edit',
|
||||
component: () => import('@/pages/TenantFormPage.vue'),
|
||||
meta: { permissions: ['hamkar:read', 'khanegi:read'], permissionMode: 'any' },
|
||||
},
|
||||
{
|
||||
path: 'versions/:id/ui',
|
||||
name: 'version-ui',
|
||||
component: () => import('@/pages/UiConfigPage.vue'),
|
||||
meta: { permissions: ['khanegi:read'] },
|
||||
},
|
||||
{
|
||||
path: 'versions/:id/ui-modular',
|
||||
name: 'version-ui-modular',
|
||||
component: () => import('@/pages/KhanegiModularUiConfigPage.vue'),
|
||||
meta: { permissions: ['khanegi:read'] },
|
||||
},
|
||||
{
|
||||
path: 'versions/:id/ui-hamkar',
|
||||
name: 'version-ui-hamkar',
|
||||
component: () => import('@/pages/HamkarUiConfigPage.vue'),
|
||||
meta: { permissions: ['hamkar:read'] },
|
||||
},
|
||||
{
|
||||
path: 'audit',
|
||||
name: 'audit',
|
||||
component: () => import('@/pages/AuditPage.vue'),
|
||||
meta: { permissions: ['audit:read'] },
|
||||
},
|
||||
// legacy redirects
|
||||
{ path: 'tenants', redirect: { name: 'home' } },
|
||||
@@ -123,6 +149,32 @@ router.beforeEach(async (to) => {
|
||||
return { name: 'login' }
|
||||
}
|
||||
}
|
||||
|
||||
const required = to.meta.permissions
|
||||
if (required?.length) {
|
||||
const mode = to.meta.permissionMode || 'all'
|
||||
const ok =
|
||||
mode === 'any' ? auth.canAny(required) : auth.canAll(required)
|
||||
|
||||
// product-versions: also enforce exact product from params
|
||||
if (to.name === 'product-versions') {
|
||||
const product = String(to.params.product || '')
|
||||
if (product === 'hamkar' && !auth.can('hamkar:read')) {
|
||||
message.warning('به این بخش دسترسی ندارید')
|
||||
return { name: 'home' }
|
||||
}
|
||||
if (product === 'khanegi' && !auth.can('khanegi:read')) {
|
||||
message.warning('به این بخش دسترسی ندارید')
|
||||
return { name: 'home' }
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
message.warning('به این بخش دسترسی ندارید')
|
||||
return { name: 'home' }
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user