From a5727f0f51ed30da4f6889fe52cad760e9347e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Wed, 4 Jun 2025 16:42:13 +0200 Subject: [PATCH] Login route, database compose file --- USEntryCoach.Server/Program.cs | 41 +++++++++++++---- docker-compose.yml | 13 ++++++ usentrycoach.client/src/App.tsx | 23 ++++++---- .../src/Components/ProtectedRoute.tsx | 46 +++++++++++++++++++ usentrycoach.client/vite.config.ts | 2 +- 5 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 docker-compose.yml diff --git a/USEntryCoach.Server/Program.cs b/USEntryCoach.Server/Program.cs index d36cc7a..7d04e0f 100644 --- a/USEntryCoach.Server/Program.cs +++ b/USEntryCoach.Server/Program.cs @@ -45,16 +45,16 @@ AuthenticationSettings? authSettings = authSettingsSection.Get -{ - options.AddPolicy(nameof(UserRole.Developer), policy => policy.RequireRole(nameof(UserRole.Developer))); - options.AddPolicy(nameof(UserRole.User), policy => - { - // Also allow Developers to do anything a user can do. - policy.RequireRole(nameof(UserRole.User), nameof(UserRole.Developer)); - }); -}); +// +// builder.Services.AddAuthorization(options => +// { +// options.AddPolicy(nameof(UserRole.Developer), policy => policy.RequireRole(nameof(UserRole.Developer))); +// options.AddPolicy(nameof(UserRole.User), policy => +// { +// // Also allow Developers to do anything a user can do. +// policy.RequireRole(nameof(UserRole.User), nameof(UserRole.Developer)); +// }); +// }); builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))); @@ -145,6 +145,27 @@ app.MapGet("/user", (ClaimsPrincipal user) => Results.Ok(new { message = $"Authenticated as { user?.Identity?.Name }" }); }).RequireAuthorization(nameof(UserRole.User)); +app.MapGet("/auth/validate", async (HttpContext context, UserManager userManager) => +{ + if (!context.User.Identity?.IsAuthenticated ?? true) + { + return Results.Unauthorized(); + } + + IdentityUser? user = await userManager.GetUserAsync(context.User); + + if (user is null) + { + return Results.InternalServerError("User not found?!"); + } + + return Results.Ok(new + { + user.Id, + user.Email + }); +}).RequireAuthorization(); + app.MapGet("/ephemeral_token", async () => { //if (apiKey == null) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d554917 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +# Use postgres/example user/password credentials + +services: + db: + image: postgres + restart: always + # set shared memory limit when using docker compose + shm_size: 128mb + environment: + POSTGRES_USER: us-entry-agent-dev + POSTGRES_PASSWORD: example + ports: + - 5432:5432 \ No newline at end of file diff --git a/usentrycoach.client/src/App.tsx b/usentrycoach.client/src/App.tsx index 29b001d..1f505bc 100644 --- a/usentrycoach.client/src/App.tsx +++ b/usentrycoach.client/src/App.tsx @@ -5,6 +5,7 @@ import useLoginToken from "./Hooks/useLoginToken.tsx"; import Home from "./Components/Home.tsx"; import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; import ProtectedRoute from "./Components/ProtectedRoute.tsx"; +import {CookiesProvider} from "react-cookie"; export default function App() { @@ -22,16 +23,18 @@ export default function App() <> {/**/} - - - } /> - } /> - }> - } /> - - Deine Mamma ist so dick, sie hat diese Seite gefressen.

} /> -
-
+ + + + } /> + } /> + }> + } /> + + Deine Mamma ist so dick, sie hat diese Seite gefressen.

} /> +
+
+
); } diff --git a/usentrycoach.client/src/Components/ProtectedRoute.tsx b/usentrycoach.client/src/Components/ProtectedRoute.tsx index cda40d5..e582250 100644 --- a/usentrycoach.client/src/Components/ProtectedRoute.tsx +++ b/usentrycoach.client/src/Components/ProtectedRoute.tsx @@ -1,8 +1,54 @@ import { Outlet } from "react-router-dom"; import Login from "./Login.tsx"; +import { useEffect } from "react"; +import { z } from 'zod/v4'; + +const AuthValidateResult = z.object({ + id: z.string(), + email: z.string() +}); export default function ProtectedRoute({user, setUser} : {user: string | null, setUser: (user: string | null) => void}) { + + async function authenticateUser () + { + try + { + console.log("Checkineasdjkf") + const response = await fetch('/auth/validate', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) + { + console.error(`Failed to validate session: ${response.status} ${response.statusText}`); + setUser(null); + return; + } + + const responseJson:unknown = await response.json(); + const parsedUser = AuthValidateResult.parse(responseJson); + + setUser(JSON.stringify(parsedUser)); + + console.log("User authorized!") + } + catch (e) + { + console.error(e); + setUser(null); + } + } + + useEffect(() => + { + void authenticateUser(); + }); + if (user === null) { return ; diff --git a/usentrycoach.client/vite.config.ts b/usentrycoach.client/vite.config.ts index c45cf69..eba1ca2 100644 --- a/usentrycoach.client/vite.config.ts +++ b/usentrycoach.client/vite.config.ts @@ -44,7 +44,7 @@ const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_H env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:7085'; // Define a list of all existing backend routes. -const backendRoutes = ['/login', '/register', '/ephemeral_token']; +const backendRoutes = ['/login', '/register', '/ephemeral_token', '/auth/validate']; // For development, we have a node.js server running that delivers our frontend. // We have to configure proxies for the backend calls, so that node.js will forward them to the backend.