feat(auth): add frontend login and route protection
This commit is contained in:
parent
6f7cae9e24
commit
4bc8b20a21
5 changed files with 116 additions and 19 deletions
|
|
@ -32,7 +32,7 @@ def login(
|
||||||
key="access_token",
|
key="access_token",
|
||||||
value=token,
|
value=token,
|
||||||
httponly=True,
|
httponly=True,
|
||||||
secure=True,
|
secure=False,
|
||||||
samesite="lax",
|
samesite="lax",
|
||||||
max_age=3600,
|
max_age=3600,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
15
frontend/athena/app/dashboard/page.tsx
Normal file
15
frontend/athena/app/dashboard/page.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
export default function DashboardPage() {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-slate-100">
|
||||||
|
<div className="mx-auto max-w-7xl p-8">
|
||||||
|
<h1 className="text-4xl font-bold">
|
||||||
|
Olympus Dashboard
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="mt-4 text-slate-600">
|
||||||
|
Willkommen bei Funktechnik Schubert.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
79
frontend/athena/app/login/page.tsx
Normal file
79
frontend/athena/app/login/page.tsx
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
async function handleLogin(e: React.FormEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
setError("");
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
router.push("/dashboard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setError("Benutzername oder Passwort ist falsch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen items-center justify-center bg-slate-100">
|
||||||
|
<form
|
||||||
|
onSubmit={handleLogin}
|
||||||
|
className="w-full max-w-md rounded-xl bg-white p-8 shadow-xl"
|
||||||
|
>
|
||||||
|
<h1 className="mb-8 text-center text-3xl font-bold">
|
||||||
|
Olympus CRM
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="mb-4 w-full rounded border p-3"
|
||||||
|
placeholder="Benutzername"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="mb-4 w-full rounded border p-3"
|
||||||
|
type="password"
|
||||||
|
placeholder="Passwort"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<p className="mb-4 text-red-600">
|
||||||
|
{error}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="w-full rounded bg-blue-600 p-3 text-white hover:bg-blue-700"
|
||||||
|
>
|
||||||
|
Anmelden
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,5 @@
|
||||||
import StatCard from "@/components/StatCard";
|
import { redirect } from "next/navigation";
|
||||||
import UserCounter from "@/components/UserCounter";
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function HomePage() {
|
||||||
return (
|
redirect("/login");
|
||||||
<>
|
|
||||||
<div className="grid grid-cols-4 gap-6">
|
|
||||||
|
|
||||||
<StatCard title="Benutzer" value={<UserCounter />} />
|
|
||||||
|
|
||||||
<StatCard title="Kunden" value="0" />
|
|
||||||
|
|
||||||
<StatCard title="Reparaturen" value="0" />
|
|
||||||
|
|
||||||
<StatCard title="Lager" value="0" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
18
frontend/athena/middleware.ts
Normal file
18
frontend/athena/middleware.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export function middleware(request: NextRequest) {
|
||||||
|
const token = request.cookies.get("access_token");
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return NextResponse.redirect(new URL("/login", request.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
"/dashboard/:path*",
|
||||||
|
"/users/:path*",
|
||||||
|
],
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue