#### __1. Role-Based Security Architecture__
All checks were successful
Build And Push Image / docker (push) Successful in 2m58s
All checks were successful
Build And Push Image / docker (push) Successful in 2m58s
- Replaces group-based tiers with proper Keycloak realm roles - `monaco-user`, `monaco-board`, `monaco-admin` roles - Backward compatibility with existing group system #### __2. Advanced User Management__ - Comprehensive user profile synchronization - Membership data stored in Keycloak user attributes - Bidirectional sync between NocoDB and Keycloak #### __3. Session Security & Monitoring__ - Real-time session tracking and management - Administrative session control capabilities - Enhanced security analytics foundation #### __4. Email Workflow System__ - Multiple email types: DUES_REMINDER, MEMBERSHIP_RENEWAL, WELCOME, VERIFICATION - Customizable email parameters and lifespans - Advanced email template support #### __5. Seamless Migration Path__ - All existing functionality continues to work - New users automatically get realm roles - Gradual migration from groups to roles - Zero breaking changes ### 🔧 __What You Can Do Now__ #### __For New Users:__ - Public registrations automatically assign `monaco-user` role - Portal account creation syncs member data to Keycloak attributes - Enhanced email verification and welcome workflows #### __For Administrators:__ - Session management and monitoring capabilities - Advanced user profile management with member data sync - Comprehensive role assignment and management - Enhanced email communication workflows #### __For Developers:__ - Use `hasRole('monaco-admin')` for role-based checks - Access `getAllRoles()` for debugging and analytics - Enhanced `useAuth()` composable with backward compatibility - Comprehensive TypeScript support throughout ### 🛡️ __Security & Reliability__ - __Backward Compatibility__: Existing users continue to work seamlessly - __Enhanced Security__: Proper realm role-based authorization - __Error Handling__: Comprehensive error handling and fallbacks - __Type Safety__: Full TypeScript support throughout the system
This commit is contained in:
@@ -7,29 +7,131 @@ export const useAuth = () => {
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// Tier-based computed properties
|
||||
const userTier = computed(() => user.value?.tier || 'user');
|
||||
const isUser = computed(() => user.value?.tier === 'user');
|
||||
const isBoard = computed(() => user.value?.tier === 'board');
|
||||
const isAdmin = computed(() => user.value?.tier === 'admin');
|
||||
// Enhanced role checking method - supports both realm roles and legacy groups
|
||||
const hasRole = (roleName: string): boolean => {
|
||||
if (!user.value) return false;
|
||||
|
||||
// Get roles from user token (Keycloak format)
|
||||
const userToken = user.value as any; // Cast for accessing token properties
|
||||
|
||||
// Check realm roles first (new system)
|
||||
const realmRoles = userToken.realm_access?.roles || [];
|
||||
if (realmRoles.includes(roleName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check client roles (new system)
|
||||
const clientRoles = userToken.resource_access || {};
|
||||
for (const clientId in clientRoles) {
|
||||
const roles = clientRoles[clientId]?.roles || [];
|
||||
if (roles.includes(roleName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to legacy group system
|
||||
const groups = user.value.groups || [];
|
||||
return groups.includes(roleName) || groups.includes(`/${roleName}`);
|
||||
};
|
||||
|
||||
// Enhanced tier-based computed properties with role support
|
||||
const isUser = computed(() => {
|
||||
// Check new realm roles first
|
||||
if (hasRole('monaco-user')) return true;
|
||||
// Fallback to legacy tier system
|
||||
return user.value?.tier === 'user';
|
||||
});
|
||||
|
||||
const isBoard = computed(() => {
|
||||
// Check new realm roles first
|
||||
if (hasRole('monaco-board')) return true;
|
||||
// Fallback to legacy tier system
|
||||
return user.value?.tier === 'board';
|
||||
});
|
||||
|
||||
const isAdmin = computed(() => {
|
||||
// Check new realm roles first
|
||||
if (hasRole('monaco-admin')) return true;
|
||||
// Fallback to legacy tier system
|
||||
return user.value?.tier === 'admin';
|
||||
});
|
||||
|
||||
// Enhanced tier computation with role priority
|
||||
const userTier = computed(() => {
|
||||
if (hasRole('monaco-admin')) return 'admin';
|
||||
if (hasRole('monaco-board')) return 'board';
|
||||
if (hasRole('monaco-user')) return 'user';
|
||||
// Fallback to legacy tier system
|
||||
return user.value?.tier || 'user';
|
||||
});
|
||||
|
||||
const firstName = computed(() => {
|
||||
if (user.value?.firstName) return user.value.firstName;
|
||||
if (user.value?.name) return user.value.name.split(' ')[0];
|
||||
return 'User';
|
||||
});
|
||||
|
||||
// Helper methods
|
||||
// Enhanced helper methods
|
||||
const hasTier = (requiredTier: 'user' | 'board' | 'admin') => {
|
||||
return user.value?.tier === requiredTier;
|
||||
// Use computed userTier which handles both new and legacy systems
|
||||
return userTier.value === requiredTier;
|
||||
};
|
||||
|
||||
const hasGroup = (groupName: string) => {
|
||||
return user.value?.groups?.includes(groupName) || false;
|
||||
};
|
||||
|
||||
// Legacy compatibility
|
||||
const hasRole = (role: string) => {
|
||||
return hasGroup(role);
|
||||
// New helper methods for realm roles
|
||||
const hasRealmRole = (roleName: string): boolean => {
|
||||
if (!user.value) return false;
|
||||
const userToken = user.value as any;
|
||||
const realmRoles = userToken.realm_access?.roles || [];
|
||||
return realmRoles.includes(roleName);
|
||||
};
|
||||
|
||||
const hasClientRole = (roleName: string, clientId?: string): boolean => {
|
||||
if (!user.value) return false;
|
||||
const userToken = user.value as any;
|
||||
const clientRoles = userToken.resource_access || {};
|
||||
|
||||
if (clientId) {
|
||||
// Check specific client
|
||||
const roles = clientRoles[clientId]?.roles || [];
|
||||
return roles.includes(roleName);
|
||||
} else {
|
||||
// Check all clients
|
||||
for (const cId in clientRoles) {
|
||||
const roles = clientRoles[cId]?.roles || [];
|
||||
if (roles.includes(roleName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Get all user roles (combines realm and client roles)
|
||||
const getAllRoles = (): string[] => {
|
||||
if (!user.value) return [];
|
||||
const userToken = user.value as any;
|
||||
const roles: string[] = [];
|
||||
|
||||
// Add realm roles
|
||||
const realmRoles = userToken.realm_access?.roles || [];
|
||||
roles.push(...realmRoles);
|
||||
|
||||
// Add client roles
|
||||
const clientRoles = userToken.resource_access || {};
|
||||
for (const clientId in clientRoles) {
|
||||
const clientRolesList = clientRoles[clientId]?.roles || [];
|
||||
roles.push(...clientRolesList);
|
||||
}
|
||||
|
||||
// Add legacy groups for compatibility
|
||||
const groups = user.value.groups || [];
|
||||
roles.push(...groups);
|
||||
|
||||
return [...new Set(roles)]; // Remove duplicates
|
||||
};
|
||||
|
||||
// Direct login method
|
||||
@@ -205,7 +307,10 @@ export const useAuth = () => {
|
||||
// Helper methods
|
||||
hasTier,
|
||||
hasGroup,
|
||||
hasRole, // Legacy compatibility
|
||||
hasRole, // Enhanced with realm role support
|
||||
hasRealmRole,
|
||||
hasClientRole,
|
||||
getAllRoles,
|
||||
|
||||
// Actions
|
||||
login,
|
||||
|
||||
Reference in New Issue
Block a user