Add role-based authorization system with admin functionality
- Implement authorization middleware and composables for role checking - Add groups/roles support to authentication and session management - Create admin dashboard pages and API endpoints - Add audit logging utility for tracking user actions - Enhance expense page with role-based access control - Improve session caching with authorization state management
This commit is contained in:
198
composables/useAuthorization.ts
Normal file
198
composables/useAuthorization.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
export interface UserWithGroups {
|
||||
id: string;
|
||||
email: string;
|
||||
username: string;
|
||||
name: string;
|
||||
authMethod: string;
|
||||
groups: string[];
|
||||
}
|
||||
|
||||
export interface AuthState {
|
||||
user: UserWithGroups | null;
|
||||
authenticated: boolean;
|
||||
groups: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization composable for role-based access control
|
||||
*/
|
||||
export const useAuthorization = () => {
|
||||
// Get the current user state from Nuxt
|
||||
const nuxtApp = useNuxtApp();
|
||||
|
||||
/**
|
||||
* Get current user groups from session
|
||||
*/
|
||||
const getUserGroups = (): string[] => {
|
||||
const authState = nuxtApp.payload.data?.authState as AuthState;
|
||||
return authState?.groups || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get current authenticated user
|
||||
*/
|
||||
const getCurrentUser = (): UserWithGroups | null => {
|
||||
const authState = nuxtApp.payload.data?.authState as AuthState;
|
||||
return authState?.user || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if user has specific role/group
|
||||
*/
|
||||
const hasRole = (role: string): boolean => {
|
||||
const groups = getUserGroups();
|
||||
return groups.includes(role);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if user has any of the specified roles
|
||||
*/
|
||||
const hasAnyRole = (roles: string[]): boolean => {
|
||||
const groups = getUserGroups();
|
||||
return roles.some(role => groups.includes(role));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if user has all of the specified roles
|
||||
*/
|
||||
const hasAllRoles = (roles: string[]): boolean => {
|
||||
const groups = getUserGroups();
|
||||
return roles.every(role => groups.includes(role));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if user can access a specific resource/feature
|
||||
*/
|
||||
const canAccess = (resource: string): boolean => {
|
||||
const groups = getUserGroups();
|
||||
|
||||
// Define access rules for different resources
|
||||
const accessRules: Record<string, string[]> = {
|
||||
'expenses': ['sales', 'admin'],
|
||||
'admin-console': ['admin'],
|
||||
'audit-logs': ['admin'],
|
||||
'system-logs': ['admin'],
|
||||
'duplicate-management': ['admin'],
|
||||
'user-management': ['admin'],
|
||||
'interests': ['user', 'sales', 'admin'],
|
||||
'berths': ['user', 'sales', 'admin'],
|
||||
'dashboard': ['user', 'sales', 'admin'],
|
||||
};
|
||||
|
||||
const requiredRoles = accessRules[resource];
|
||||
if (!requiredRoles) {
|
||||
// If no specific rules defined, allow for authenticated users
|
||||
return groups.length > 0;
|
||||
}
|
||||
|
||||
return hasAnyRole(requiredRoles);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience methods for common role checks
|
||||
*/
|
||||
const isAdmin = (): boolean => hasRole('admin');
|
||||
const isSales = (): boolean => hasRole('sales');
|
||||
const isUser = (): boolean => hasRole('user');
|
||||
const isSalesOrAdmin = (): boolean => hasAnyRole(['sales', 'admin']);
|
||||
const isUserOrAbove = (): boolean => hasAnyRole(['user', 'sales', 'admin']);
|
||||
|
||||
/**
|
||||
* Get user's highest role (for display purposes)
|
||||
*/
|
||||
const getHighestRole = (): string => {
|
||||
const groups = getUserGroups();
|
||||
if (groups.includes('admin')) return 'admin';
|
||||
if (groups.includes('sales')) return 'sales';
|
||||
if (groups.includes('user')) return 'user';
|
||||
return 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get role display name
|
||||
*/
|
||||
const getRoleDisplayName = (role: string): string => {
|
||||
const roleNames: Record<string, string> = {
|
||||
'admin': 'Administrator',
|
||||
'sales': 'Sales Team',
|
||||
'user': 'User',
|
||||
'none': 'No Access'
|
||||
};
|
||||
return roleNames[role] || role;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get role color for UI display
|
||||
*/
|
||||
const getRoleColor = (role: string): string => {
|
||||
const roleColors: Record<string, string> = {
|
||||
'admin': 'red',
|
||||
'sales': 'purple',
|
||||
'user': 'blue',
|
||||
'none': 'grey'
|
||||
};
|
||||
return roleColors[role] || 'grey';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if current route requires specific roles
|
||||
*/
|
||||
const checkRouteAccess = (route: any): boolean => {
|
||||
if (!route.meta?.roles) {
|
||||
// No role requirements, allow access
|
||||
return true;
|
||||
}
|
||||
|
||||
const requiredRoles = Array.isArray(route.meta.roles) ? route.meta.roles : [route.meta.roles];
|
||||
return hasAnyRole(requiredRoles);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get navigation items filtered by user permissions
|
||||
*/
|
||||
const getFilteredNavigation = (navigationItems: any[]): any[] => {
|
||||
return navigationItems.filter(item => {
|
||||
if (!item.roles) return true; // No role restrictions
|
||||
return hasAnyRole(item.roles);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update auth state (called by middleware)
|
||||
*/
|
||||
const updateAuthState = (authState: AuthState) => {
|
||||
if (!nuxtApp.payload.data) {
|
||||
nuxtApp.payload.data = {};
|
||||
}
|
||||
nuxtApp.payload.data.authState = authState;
|
||||
};
|
||||
|
||||
return {
|
||||
// State getters
|
||||
getUserGroups,
|
||||
getCurrentUser,
|
||||
|
||||
// Role checking
|
||||
hasRole,
|
||||
hasAnyRole,
|
||||
hasAllRoles,
|
||||
canAccess,
|
||||
|
||||
// Convenience methods
|
||||
isAdmin,
|
||||
isSales,
|
||||
isUser,
|
||||
isSalesOrAdmin,
|
||||
isUserOrAbove,
|
||||
|
||||
// Utility methods
|
||||
getHighestRole,
|
||||
getRoleDisplayName,
|
||||
getRoleColor,
|
||||
checkRouteAccess,
|
||||
getFilteredNavigation,
|
||||
|
||||
// State management
|
||||
updateAuthState
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user