Refactor authentication handling in Portal application
- Transitioned from server-side session management to client-side using `useSession` from `next-auth/react`. - Added loading and unauthenticated states with user-friendly sign-in prompts in the Home and VMs pages. - Enhanced `auth.ts` to conditionally configure authentication providers based on Keycloak setup, with a fallback to a credentials provider for development mode. - Improved session management to include user details when using credentials provider.
This commit is contained in:
62
portal/src/app/api/auth/error/page.tsx
Normal file
62
portal/src/app/api/auth/error/page.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
'use client';
|
||||
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
function AuthErrorContent() {
|
||||
const searchParams = useSearchParams();
|
||||
const error = searchParams.get('error');
|
||||
|
||||
const errorMessages: Record<string, string> = {
|
||||
Configuration: 'There is a problem with the server configuration.',
|
||||
AccessDenied: 'You do not have permission to sign in.',
|
||||
Verification: 'The verification token has expired or has already been used.',
|
||||
Default: 'An error occurred during authentication.',
|
||||
};
|
||||
|
||||
const errorMessage = error && errorMessages[error]
|
||||
? errorMessages[error]
|
||||
: errorMessages.Default;
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center max-w-md mx-auto p-8">
|
||||
<h1 className="text-2xl font-bold text-white mb-4">Authentication Error</h1>
|
||||
<p className="text-gray-400 mb-2">{errorMessage}</p>
|
||||
{error && (
|
||||
<p className="text-sm text-gray-500 mb-6">Error code: {error}</p>
|
||||
)}
|
||||
<div className="flex gap-4 justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors inline-block"
|
||||
>
|
||||
Go Home
|
||||
</Link>
|
||||
<Link
|
||||
href="/api/auth/signin"
|
||||
className="px-6 py-3 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors inline-block"
|
||||
>
|
||||
Try Again
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AuthErrorPage() {
|
||||
return (
|
||||
<Suspense fallback={
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 h-8 w-8 animate-spin rounded-full border-4 border-gray-300 border-t-blue-600 mx-auto"></div>
|
||||
<p className="text-gray-400">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
}>
|
||||
<AuthErrorContent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,41 @@
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
'use client';
|
||||
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { signIn } from 'next-auth/react';
|
||||
import Dashboard from '@/components/Dashboard';
|
||||
|
||||
export default async function Home() {
|
||||
const session = await getServerSession(authOptions);
|
||||
export default function Home() {
|
||||
const { data: session, status } = useSession();
|
||||
|
||||
if (!session) {
|
||||
redirect('/api/auth/signin');
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 h-8 w-8 animate-spin rounded-full border-4 border-gray-300 border-t-blue-600 mx-auto"></div>
|
||||
<p className="text-gray-400">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === 'unauthenticated') {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center max-w-md mx-auto p-8">
|
||||
<h1 className="text-2xl font-bold text-white mb-4">Welcome to Portal</h1>
|
||||
<p className="text-gray-400 mb-6">Please sign in to continue</p>
|
||||
<button
|
||||
onClick={() => signIn()}
|
||||
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Sign In
|
||||
</button>
|
||||
<p className="text-sm text-gray-500 mt-4">
|
||||
Development mode: Use any email/password
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <Dashboard />;
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
'use client';
|
||||
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { signIn } from 'next-auth/react';
|
||||
import VMList from '@/components/vms/VMList';
|
||||
|
||||
export default async function VMsPage() {
|
||||
const session = await getServerSession(authOptions);
|
||||
export default function VMsPage() {
|
||||
const { data: session, status } = useSession();
|
||||
|
||||
if (!session) {
|
||||
redirect('/api/auth/signin');
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 h-8 w-8 animate-spin rounded-full border-4 border-gray-300 border-t-blue-600 mx-auto"></div>
|
||||
<p className="text-gray-400">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === 'unauthenticated') {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-900">
|
||||
<div className="text-center max-w-md mx-auto p-8">
|
||||
<h1 className="text-2xl font-bold text-white mb-4">Authentication Required</h1>
|
||||
<p className="text-gray-400 mb-6">Please sign in to view virtual machines</p>
|
||||
<button
|
||||
onClick={() => signIn()}
|
||||
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Sign In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user