adding middleware
This commit is contained in:
parent
abad2cec96
commit
65cccb9620
15 changed files with 115 additions and 28 deletions
|
@ -3,6 +3,7 @@ import { defineConfig } from "astro/config";
|
|||
import react from "@astrojs/react";
|
||||
import node from "@astrojs/node";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [react()],
|
||||
output: "server",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
14
package.json
14
package.json
|
@ -4,24 +4,24 @@
|
|||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "bunx --bun astro dev",
|
||||
"start": "bunx --bun astro dev",
|
||||
"build": "rm -rf dist && bunx --bun astro check && bunx --bun astro build",
|
||||
"preview": "bunx --bun astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.7.0",
|
||||
"@astrojs/node": "^8.2.5",
|
||||
"@astrojs/react": "^3.4.0",
|
||||
"@types/react": "^18.3.2",
|
||||
"@astrojs/node": "^8.3.2",
|
||||
"@astrojs/react": "^3.6.0",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"astro": "^4.9.1",
|
||||
"astro": "^4.11.3",
|
||||
"bootstrap": "^5.3.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"typescript": "^5.3.3"
|
||||
"react-icons": "^5.2.1",
|
||||
"typescript": "^5.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.7.3"
|
||||
"@biomejs/biome": "1.8.3"
|
||||
}
|
||||
}
|
||||
|
|
3
src/components/Header.astro
Normal file
3
src/components/Header.astro
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div class="col-auto"><a href="/home">Movies</a></div>
|
||||
<div class="col-auto"><a href="/home/settings">Settings</a></div>
|
||||
<div class="col-auto"><a href="/logout">Logout</a></div>
|
|
@ -2,7 +2,9 @@ import LoginForm, { type LoginFormValue } from "./LoginForm";
|
|||
|
||||
export default function LoginFormData() {
|
||||
function handleOnFormSubmit(data: LoginFormValue) {
|
||||
fetch(`${import.meta.env.PUBLIC_API_URL}/accounts/login`, {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
fetch("/api/accounts/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
credentials: "include",
|
||||
|
@ -13,7 +15,7 @@ export default function LoginFormData() {
|
|||
})
|
||||
.then((res) => res.json())
|
||||
.then((json) => {
|
||||
window.location.href = "/home";
|
||||
window.location.href = searchParams.get("redirect") || "/home";
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
import Header from "../components/Header.astro";
|
||||
import RootLayout from "./RootLayout.astro";
|
||||
|
||||
interface Props {
|
||||
|
@ -8,13 +9,11 @@ interface Props {
|
|||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<RootLayout title={title}>
|
||||
<RootLayout title={`Trepa - ${title}`}>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">Films</div>
|
||||
<div class="col-auto">Compte</div>
|
||||
<div class="col-auto">Deconnexion</div>
|
||||
<Header />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<slot />
|
||||
|
@ -22,4 +21,17 @@ const { title } = Astro.props;
|
|||
</div>
|
||||
</RootLayout>
|
||||
|
||||
<script></script>
|
||||
<script>
|
||||
const logoutElt = document.getElementById("logout-btn");
|
||||
|
||||
logoutElt?.addEventListener("click", () => {
|
||||
fetch(`${import.meta.env.PUBLIC_API_URL}/accounts/logout`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then(() => {
|
||||
window.location.href = "/";
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,22 +2,25 @@ import { defineMiddleware, sequence } from "astro:middleware";
|
|||
|
||||
const protectedRoutes = defineMiddleware(async (ctx, next) => {
|
||||
const pathname = ctx.url.pathname;
|
||||
if (!["/", "/register"].includes(pathname)) {
|
||||
const jwt = ctx.cookies.get("token");
|
||||
if (
|
||||
!["/", "/register", "/logout"].includes(pathname) &&
|
||||
!pathname.startsWith("/api")
|
||||
) {
|
||||
const jwt = ctx.cookies.get("jwt");
|
||||
if (!jwt) {
|
||||
return ctx.redirect("/");
|
||||
return ctx.redirect(`/?redirect=${pathname}`);
|
||||
}
|
||||
|
||||
const res = await fetch(
|
||||
`${import.meta.env.PUBLIC_API_URL}/accounts/recovery`,
|
||||
{
|
||||
const jwtValue = jwt.value;
|
||||
const res = await fetch(`${import.meta.env.API_URL}/accounts/recovery`, {
|
||||
credentials: "include",
|
||||
headers: ctx.request.headers,
|
||||
headers: {
|
||||
Authorization: `Bearer ${jwtValue}`,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
if (res.status !== 201) {
|
||||
return ctx.redirect("/");
|
||||
if (res.status !== 200) {
|
||||
return ctx.redirect(`/?redirect=${pathname}`);
|
||||
}
|
||||
|
||||
ctx.locals.account = JSON.parse(await res.text()).account;
|
||||
|
|
28
src/pages/api/accounts/login.ts
Normal file
28
src/pages/api/accounts/login.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import type { APIRoute } from "astro";
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
const reqBody = await request.text();
|
||||
if (!reqBody) throw new Error("body not found");
|
||||
|
||||
const res = await fetch(`${import.meta.env.API_URL}/accounts/login`, {
|
||||
method: "POST",
|
||||
body: reqBody,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const resBody = await res.text();
|
||||
const resBodyJson = JSON.parse(resBody);
|
||||
|
||||
if (res.status === 201 && resBodyJson?.jwt) {
|
||||
cookies.set("jwt", resBodyJson.jwt, {
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
sameSite: "strict",
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(resBody, { status: res.status });
|
||||
};
|
|
@ -4,6 +4,6 @@ import HomeLayout from "../../layouts/HomeLayout.astro";
|
|||
const account = Astro.locals.account;
|
||||
---
|
||||
|
||||
<HomeLayout title="Trepa">
|
||||
<HomeLayout title="Movies">
|
||||
Hello {account?.username}
|
||||
</HomeLayout>
|
||||
|
|
0
src/pages/home/settings/account.astro
Normal file
0
src/pages/home/settings/account.astro
Normal file
0
src/pages/home/settings/accounts.astro
Normal file
0
src/pages/home/settings/accounts.astro
Normal file
34
src/pages/home/settings/index.astro
Normal file
34
src/pages/home/settings/index.astro
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
import {
|
||||
MdAccountBox,
|
||||
MdAdminPanelSettings,
|
||||
MdOutlineLocalMovies,
|
||||
} from "react-icons/md";
|
||||
|
||||
import HomeLayout from "../../../layouts/HomeLayout.astro";
|
||||
---
|
||||
|
||||
<HomeLayout title="Settings">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-4">
|
||||
<div class="list-group">
|
||||
<a
|
||||
href="/home/settings/account"
|
||||
class="list-group-item list-group-item-action"
|
||||
>
|
||||
<MdAccountBox /> My account
|
||||
</a>
|
||||
<a
|
||||
href="/home/settings/accounts"
|
||||
class="list-group-item list-group-item-action"
|
||||
><MdAdminPanelSettings /> Accounts</a
|
||||
>
|
||||
<a
|
||||
href="/home/settings/movies"
|
||||
class="list-group-item list-group-item-action"
|
||||
><MdOutlineLocalMovies /> Movies</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HomeLayout>
|
0
src/pages/home/settings/movies.astro
Normal file
0
src/pages/home/settings/movies.astro
Normal file
4
src/pages/logout.astro
Normal file
4
src/pages/logout.astro
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Astro.cookies.delete("jwt");
|
||||
return Astro.redirect("/");
|
||||
---
|
Loading…
Reference in a new issue