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.