Refactor authentication system with tier-based access control
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
- Replace group-based auth with user/board/admin tier system - Add direct login functionality alongside OAuth - Implement role-based middleware for route protection - Create dashboard pages and admin API endpoints - Add error handling page and improved user management - Maintain backward compatibility with legacy role methods
This commit is contained in:
@@ -1,64 +1,156 @@
|
||||
import type { AuthState } from '~/utils/types';
|
||||
import type { User } from '~/utils/types';
|
||||
|
||||
export const useAuth = () => {
|
||||
const authState = useState<AuthState>('auth.state', () => ({
|
||||
authenticated: false,
|
||||
user: null,
|
||||
groups: [],
|
||||
}));
|
||||
const user = ref<User | null>(null);
|
||||
const isAuthenticated = computed(() => !!user.value);
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
const login = () => {
|
||||
return navigateTo('/api/auth/login');
|
||||
// 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');
|
||||
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
|
||||
const hasTier = (requiredTier: 'user' | 'board' | 'admin') => {
|
||||
return user.value?.tier === requiredTier;
|
||||
};
|
||||
|
||||
const logout = async () => {
|
||||
const hasGroup = (groupName: string) => {
|
||||
return user.value?.groups?.includes(groupName) || false;
|
||||
};
|
||||
|
||||
// Legacy compatibility
|
||||
const hasRole = (role: string) => {
|
||||
return hasGroup(role);
|
||||
};
|
||||
|
||||
// Direct login method
|
||||
const login = async (credentials: { username: string; password: string; rememberMe?: boolean }) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
await $fetch('/api/auth/logout', { method: 'POST' });
|
||||
authState.value = {
|
||||
authenticated: false,
|
||||
user: null,
|
||||
groups: [],
|
||||
};
|
||||
await navigateTo('/login');
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
await navigateTo('/login');
|
||||
const response = await $fetch<{
|
||||
success: boolean;
|
||||
redirectTo?: string;
|
||||
user?: User;
|
||||
}>('/api/auth/direct-login', {
|
||||
method: 'POST',
|
||||
body: credentials
|
||||
});
|
||||
|
||||
if (response.success && response.user) {
|
||||
user.value = response.user;
|
||||
|
||||
// Redirect to dashboard or intended page
|
||||
await navigateTo(response.redirectTo || '/dashboard');
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
return { success: false, error: 'Login failed' };
|
||||
} catch (err: any) {
|
||||
error.value = err.data?.message || 'Login failed';
|
||||
return { success: false, error: error.value };
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// OAuth login method (fallback)
|
||||
const loginOAuth = () => {
|
||||
return navigateTo('/api/auth/login');
|
||||
};
|
||||
|
||||
// Password reset method
|
||||
const requestPasswordReset = async (email: string) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await $fetch<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
}>('/api/auth/forgot-password', {
|
||||
method: 'POST',
|
||||
body: { email }
|
||||
});
|
||||
|
||||
return { success: true, message: response.message };
|
||||
} catch (err: any) {
|
||||
error.value = err.data?.message || 'Password reset failed';
|
||||
return { success: false, error: error.value };
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Check authentication status
|
||||
const checkAuth = async () => {
|
||||
try {
|
||||
const response = await $fetch<AuthState>('/api/auth/session');
|
||||
authState.value = response;
|
||||
return response.authenticated;
|
||||
} catch (error) {
|
||||
console.error('Auth check error:', error);
|
||||
authState.value = {
|
||||
authenticated: false,
|
||||
user: null,
|
||||
groups: [],
|
||||
};
|
||||
const response = await $fetch<{
|
||||
authenticated: boolean;
|
||||
user: User | null;
|
||||
}>('/api/auth/session');
|
||||
|
||||
if (response.authenticated && response.user) {
|
||||
user.value = response.user;
|
||||
return true;
|
||||
} else {
|
||||
user.value = null;
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Auth check error:', err);
|
||||
user.value = null;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const isAdmin = computed(() => {
|
||||
return authState.value.groups?.includes('admin') || false;
|
||||
});
|
||||
|
||||
const hasRole = (role: string) => {
|
||||
return authState.value.groups?.includes(role) || false;
|
||||
// Logout method
|
||||
const logout = async () => {
|
||||
try {
|
||||
await $fetch('/api/auth/logout', { method: 'POST' });
|
||||
user.value = null;
|
||||
await navigateTo('/login');
|
||||
} catch (err) {
|
||||
console.error('Logout error:', err);
|
||||
user.value = null;
|
||||
await navigateTo('/login');
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
authState: readonly(authState),
|
||||
user: computed(() => authState.value.user),
|
||||
authenticated: computed(() => authState.value.authenticated),
|
||||
groups: computed(() => authState.value.groups),
|
||||
// State
|
||||
user: readonly(user),
|
||||
isAuthenticated,
|
||||
loading: readonly(loading),
|
||||
error: readonly(error),
|
||||
|
||||
// Tier-based properties
|
||||
userTier,
|
||||
isUser,
|
||||
isBoard,
|
||||
isAdmin,
|
||||
hasRole,
|
||||
firstName,
|
||||
|
||||
// Helper methods
|
||||
hasTier,
|
||||
hasGroup,
|
||||
hasRole, // Legacy compatibility
|
||||
|
||||
// Actions
|
||||
login,
|
||||
loginOAuth,
|
||||
logout,
|
||||
requestPasswordReset,
|
||||
checkAuth,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user