- Updated README.md to reflect the new project name and provide an overview of the Role-Based Access Control (RBAC) system. - Added new components for RBAC management, including: - PermissionExample.vue: Demonstrates permission-based navigation. - GroupCard.vue: Displays group information and assigned roles. - PermissionMatrix.vue: Visual representation of permissions across roles and resources. - RoleTemplates.vue: Quick role templates for applying pre-configured permissions. - StatsCards.vue: Displays statistics related to users, groups, and roles. - Introduced useRbacPermissions.js for managing permission checks. - Created docker-compose.yml for PostgreSQL and Redis services. - Developed comprehensive documentation for application management and Authentik integration. - Added multiple pages for managing applications, groups, roles, and users, including bulk operations and templates. - Updated navigation structure to include new RBAC management paths.
300 lines
9.4 KiB
Vue
300 lines
9.4 KiB
Vue
<template>
|
|
<div class="permission-example">
|
|
<h2 class="text-xl font-bold mb-4">RBAC Permission System Example</h2>
|
|
|
|
<!-- Menu Navigation Example -->
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium mb-2">Menu Items (Permission-Based)</h3>
|
|
<nav class="flex space-x-4">
|
|
<NuxtLink
|
|
v-if="canViewDashboard"
|
|
to="/dashboard"
|
|
class="px-3 py-2 bg-blue-100 text-blue-800 rounded"
|
|
>
|
|
Dashboard
|
|
</NuxtLink>
|
|
|
|
<NuxtLink
|
|
v-if="canViewUsers"
|
|
to="/users"
|
|
class="px-3 py-2 bg-green-100 text-green-800 rounded"
|
|
>
|
|
Users
|
|
</NuxtLink>
|
|
|
|
<NuxtLink
|
|
v-if="canViewRBAC"
|
|
to="/rbac"
|
|
class="px-3 py-2 bg-purple-100 text-purple-800 rounded"
|
|
>
|
|
RBAC Management
|
|
</NuxtLink>
|
|
|
|
<span v-if="!canViewDashboard && !canViewUsers && !canViewRBAC" class="text-gray-500">
|
|
No menu items available
|
|
</span>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Component-Level Permissions -->
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium mb-2">User Actions (Component Permissions)</h3>
|
|
<div class="space-y-2">
|
|
<div class="flex items-center space-x-2">
|
|
<span class="text-gray-700">John Doe</span>
|
|
<span class="text-gray-500">john@example.com</span>
|
|
|
|
<!-- Edit Button -->
|
|
<button
|
|
v-if="canEditUser"
|
|
@click="editUser"
|
|
class="px-3 py-1 bg-blue-500 text-white text-sm rounded hover:bg-blue-600"
|
|
>
|
|
<Icon name="ph:pencil" class="w-4 h-4 mr-1" />
|
|
Edit
|
|
</button>
|
|
|
|
<!-- Delete Button -->
|
|
<button
|
|
v-if="canDeleteUser"
|
|
@click="deleteUser"
|
|
class="px-3 py-1 bg-red-500 text-white text-sm rounded hover:bg-red-600"
|
|
>
|
|
<Icon name="ph:trash" class="w-4 h-4 mr-1" />
|
|
Delete
|
|
</button>
|
|
|
|
<!-- Sensitive Info (Conditional Display) -->
|
|
<span
|
|
v-if="canViewSensitiveInfo"
|
|
class="px-2 py-1 bg-yellow-100 text-yellow-800 text-xs rounded"
|
|
>
|
|
Salary: $75,000
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Feature-Level Permissions -->
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium mb-2">Advanced Features</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<!-- Data Export -->
|
|
<div class="p-4 border rounded-lg">
|
|
<h4 class="font-medium mb-2">Data Export</h4>
|
|
<button
|
|
v-if="canExportData"
|
|
@click="exportData"
|
|
class="w-full px-3 py-2 bg-green-500 text-white rounded hover:bg-green-600"
|
|
>
|
|
<Icon name="ph:download" class="w-4 h-4 mr-1" />
|
|
Export Data
|
|
</button>
|
|
<p v-else class="text-sm text-gray-500">Export not available</p>
|
|
</div>
|
|
|
|
<!-- Approval Workflow -->
|
|
<div class="p-4 border rounded-lg">
|
|
<h4 class="font-medium mb-2">Approvals</h4>
|
|
<button
|
|
v-if="canApproveRequests"
|
|
@click="approveRequest"
|
|
class="w-full px-3 py-2 bg-orange-500 text-white rounded hover:bg-orange-600"
|
|
>
|
|
<Icon name="ph:check" class="w-4 h-4 mr-1" />
|
|
Approve Requests
|
|
</button>
|
|
<p v-else class="text-sm text-gray-500">Approval not available</p>
|
|
</div>
|
|
|
|
<!-- System Backup -->
|
|
<div class="p-4 border rounded-lg">
|
|
<h4 class="font-medium mb-2">System Backup</h4>
|
|
<button
|
|
v-if="canSystemBackup"
|
|
@click="createBackup"
|
|
class="w-full px-3 py-2 bg-red-500 text-white rounded hover:bg-red-600"
|
|
>
|
|
<Icon name="ph:database" class="w-4 h-4 mr-1" />
|
|
Create Backup
|
|
</button>
|
|
<p v-else class="text-sm text-gray-500">Backup not available</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reactive Permission Example -->
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium mb-2">Reactive Permission Check</h3>
|
|
<div class="p-4 bg-gray-50 rounded-lg">
|
|
<p class="text-sm mb-2">This demonstrates reactive permission checking:</p>
|
|
|
|
<div class="space-y-2">
|
|
<div v-if="bulkActionPermission.isLoading" class="text-gray-500">
|
|
<Icon name="ph:spinner" class="w-4 h-4 animate-spin mr-1" />
|
|
Checking bulk action permission...
|
|
</div>
|
|
|
|
<div v-else-if="bulkActionPermission.isAllowed" class="text-green-600">
|
|
<Icon name="ph:check-circle" class="w-4 h-4 mr-1" />
|
|
Bulk actions are enabled for your role
|
|
</div>
|
|
|
|
<div v-else class="text-red-600">
|
|
<Icon name="ph:x-circle" class="w-4 h-4 mr-1" />
|
|
Bulk actions are not available for your role
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
@click="bulkActionPermission.checkPermission()"
|
|
class="mt-2 px-3 py-1 bg-blue-500 text-white text-sm rounded hover:bg-blue-600"
|
|
>
|
|
Recheck Permission
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Permission Summary -->
|
|
<div class="bg-blue-50 p-4 rounded-lg">
|
|
<h3 class="text-lg font-medium mb-2">Your Current Permissions</h3>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-2 text-sm">
|
|
<div :class="canViewDashboard ? 'text-green-600' : 'text-red-600'">
|
|
<Icon :name="canViewDashboard ? 'ph:check' : 'ph:x'" class="w-4 h-4 mr-1" />
|
|
Dashboard Access
|
|
</div>
|
|
<div :class="canEditUser ? 'text-green-600' : 'text-red-600'">
|
|
<Icon :name="canEditUser ? 'ph:check' : 'ph:x'" class="w-4 h-4 mr-1" />
|
|
Edit Users
|
|
</div>
|
|
<div :class="canExportData ? 'text-green-600' : 'text-red-600'">
|
|
<Icon :name="canExportData ? 'ph:check' : 'ph:x'" class="w-4 h-4 mr-1" />
|
|
Export Data
|
|
</div>
|
|
<div :class="canApproveRequests ? 'text-green-600' : 'text-red-600'">
|
|
<Icon :name="canApproveRequests ? 'ph:check' : 'ph:x'" class="w-4 h-4 mr-1" />
|
|
Approve Requests
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
useRbacPermissions,
|
|
useReactivePermission,
|
|
PERMISSION_KEYS,
|
|
PERMISSION_ACTIONS
|
|
} from '~/composables/useRbacPermissions'
|
|
|
|
// Initialize permission composable
|
|
const {
|
|
hasPermission,
|
|
canAccessMenu,
|
|
canSeeComponent,
|
|
canPerformAction,
|
|
preloadPermissions
|
|
} = useRbacPermissions()
|
|
|
|
// Menu permissions (reactive)
|
|
const canViewDashboard = ref(false)
|
|
const canViewUsers = ref(false)
|
|
const canViewRBAC = ref(false)
|
|
|
|
// Component permissions (reactive)
|
|
const canEditUser = ref(false)
|
|
const canDeleteUser = ref(false)
|
|
const canViewSensitiveInfo = ref(false)
|
|
|
|
// Feature permissions (reactive)
|
|
const canExportData = ref(false)
|
|
const canApproveRequests = ref(false)
|
|
const canSystemBackup = ref(false)
|
|
|
|
// Reactive permission example using composable
|
|
const bulkActionPermission = useReactivePermission(PERMISSION_KEYS.COMPONENT.USER_BULK_ACTIONS)
|
|
|
|
// Preload all required permissions for better performance
|
|
const requiredPermissions = [
|
|
PERMISSION_KEYS.MENU.DASHBOARD,
|
|
PERMISSION_KEYS.MENU.USERS,
|
|
PERMISSION_KEYS.MENU.RBAC,
|
|
PERMISSION_KEYS.COMPONENT.USER_EDIT_BUTTON,
|
|
PERMISSION_KEYS.COMPONENT.USER_DELETE_BUTTON,
|
|
PERMISSION_KEYS.COMPONENT.PROFILE_SENSITIVE_INFO,
|
|
PERMISSION_KEYS.FEATURE.EXPORT_DATA,
|
|
PERMISSION_KEYS.FEATURE.APPROVE_REQUESTS,
|
|
PERMISSION_KEYS.FEATURE.SYSTEM_BACKUP
|
|
]
|
|
|
|
// Check all permissions on component mount
|
|
onMounted(async () => {
|
|
try {
|
|
// Preload permissions for better performance
|
|
await preloadPermissions(requiredPermissions)
|
|
|
|
// Check menu permissions
|
|
canViewDashboard.value = await canAccessMenu('/dashboard')
|
|
canViewUsers.value = await canAccessMenu('/users')
|
|
canViewRBAC.value = await canAccessMenu('/rbac')
|
|
|
|
// Check component permissions
|
|
canEditUser.value = await canSeeComponent(PERMISSION_KEYS.COMPONENT.USER_EDIT_BUTTON)
|
|
canDeleteUser.value = await canSeeComponent(PERMISSION_KEYS.COMPONENT.USER_DELETE_BUTTON)
|
|
canViewSensitiveInfo.value = await canSeeComponent(PERMISSION_KEYS.COMPONENT.PROFILE_SENSITIVE_INFO)
|
|
|
|
// Check feature permissions
|
|
canExportData.value = await canPerformAction(PERMISSION_KEYS.FEATURE.EXPORT_DATA, PERMISSION_ACTIONS.EXPORT)
|
|
canApproveRequests.value = await canPerformAction(PERMISSION_KEYS.FEATURE.APPROVE_REQUESTS, PERMISSION_ACTIONS.APPROVE)
|
|
canSystemBackup.value = await canPerformAction(PERMISSION_KEYS.FEATURE.SYSTEM_BACKUP, PERMISSION_ACTIONS.CREATE)
|
|
} catch (error) {
|
|
console.error('Failed to load permissions:', error)
|
|
}
|
|
})
|
|
|
|
// Action handlers
|
|
const editUser = () => {
|
|
console.log('Edit user action')
|
|
// Implementation here
|
|
}
|
|
|
|
const deleteUser = () => {
|
|
console.log('Delete user action')
|
|
// Implementation here
|
|
}
|
|
|
|
const exportData = () => {
|
|
console.log('Export data action')
|
|
// Implementation here
|
|
}
|
|
|
|
const approveRequest = () => {
|
|
console.log('Approve request action')
|
|
// Implementation here
|
|
}
|
|
|
|
const createBackup = () => {
|
|
console.log('Create backup action')
|
|
// Implementation here
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.permission-example {
|
|
@apply max-w-4xl mx-auto p-6;
|
|
}
|
|
|
|
.animate-spin {
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style> |