feat: inelegant and buggy version of auth

This commit is contained in:
julius 2025-02-16 17:22:36 +01:00
parent fbe17479f7
commit 15c9a64de2
Signed by: julius
GPG Key ID: C80A63E6A5FD7092
5 changed files with 121 additions and 19 deletions

View File

@ -1,6 +1,6 @@
from datetime import timedelta, timezone, datetime
from typing import Annotated
from fastapi import Depends, HTTPException, status
from fastapi import Depends, HTTPException, Response, status
from pydantic import BaseModel
import jwt
from jwt.exceptions import InvalidTokenError
@ -102,7 +102,7 @@ async def get_current_active_user(
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
form_data: Annotated[OAuth2PasswordRequestForm, Depends()], response: Response
) -> Token:
user = authenticate_user(form_data.username, form_data.password)
if not user:
@ -115,6 +115,9 @@ async def login_for_access_token(
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
response.set_cookie(
"Authorization", value=f"Bearer {access_token}", httponly=True, samesite="none"
)
return Token(access_token=access_token, token_type="bearer")

View File

@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
import { baseUrl } from "./api";
import { apiAuth, baseUrl, token } from "./api";
import useAuthContext from "./AuthContext";
//const debounce = <T extends (...args: any[]) => void>(
// func: T,
@ -61,18 +62,14 @@ export default function Analysis() {
// Function to generate and fetch the graph image
async function loadImage() {
setLoading(true);
await fetch(`${baseUrl}api/analysis/image`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params)
})
.then((resp) => resp.json())
await apiAuth("analysis/image", params, "POST")
.then((data) => {
setImage(data.image);
setLoading(false);
});
}).catch((e) => {
const { checkAuth } = useAuthContext();
checkAuth();
})
}
useEffect(() => {
@ -92,6 +89,9 @@ export default function Analysis() {
}
}
const { user } = useAuthContext()!
console.log(`logged in as ${user.username}`);
return (
<div className="stack column dropdown">
<button onClick={() => setShowControlPanel(!showControlPanel)}>

View File

@ -12,16 +12,17 @@ body {
height: 100%;
}
footer {
font-size: x-small;
}
#root {
max-width: 1280px;
margin: 0 auto;
padding: 8px;
}
footer {
font-size: x-small;
}
.grey {
color: #444;
}
@ -37,6 +38,11 @@ footer {
z-index: -1;
}
input {
padding: 0.2em 16px;
margin-bottom: 0.5em;
}
h1,
h2,
h3 {
@ -120,7 +126,8 @@ h3 {
margin: auto;
}
button {
button,
.button {
font-weight: bold;
font-size: large;
color: aliceblue;

View File

@ -1,9 +1,10 @@
import Analysis from "./Analysis";
import "./App.css";
import { AuthProvider } from "./AuthContext";
import Footer from "./Footer";
import Header from "./Header";
import Rankings from "./Rankings";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { BrowserRouter, Routes, Route } from "react-router";
function App() {
//const [data, setData] = useState({ nodes: [], links: [] } as SociogramData);
@ -17,7 +18,11 @@ function App() {
<Header />
<Routes>
<Route index element={<Rankings />} />
<Route path="/analysis" element={<Analysis />} />
<Route path="/analysis" element={
<AuthProvider>
<Analysis />
</AuthProvider>
} />
</Routes>
<Footer />
</BrowserRouter>

View File

@ -1,4 +1,10 @@
import { useContext } from "react";
import useAuthContext from "./AuthContext";
import { createCookie } from "react-router";
export const baseUrl = import.meta.env.VITE_BASE_URL as string;
export const token = () => localStorage.getItem("access_token") as string;
export default async function api(path: string, data: any): Promise<any> {
const request = new Request(`${baseUrl}${path}/`, {
method: "POST",
@ -15,3 +21,84 @@ export default async function api(path: string, data: any): Promise<any> {
}
return response;
}
export async function apiAuth(path: string, data: any, method: string = "GET"): Promise<any> {
const req = new Request(`${baseUrl}api/${path}`, {
method: method, headers: {
"Authorization": `Bearer ${token()} `,
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
});
let resp: Response;
try {
resp = await fetch(req);
} catch (e) {
throw new Error(`request failed: ${e}`);
}
if (!resp.ok) {
if (resp.status === 401) {
logout()
throw new Error('Unauthorized');
}
}
return resp.json()
}
export type User = {
username: string;
fullName: string;
}
export async function currentUser(): Promise<User> {
if (!token()) throw new Error("you have no access token")
const req = new Request(`${baseUrl}api/users/me/`, {
method: "GET", headers: {
"Authorization": `Bearer ${token()} `,
'Content-Type': 'application/json'
}
});
let resp: Response;
try {
resp = await fetch(req);
} catch (e) {
throw new Error(`request failed: ${e}`);
}
if (!resp.ok) {
if (resp.status === 401) {
logout()
throw new Error('Unauthorized');
}
}
return resp.json() as Promise<User>;
}
export type LoginRequest = {
username: string;
password: string;
};
export type Token = {
access_token: string;
token_type: string;
};
export const login = (req: LoginRequest) => {
fetch(`${baseUrl}api/token`, {
method: "POST", headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}, body: new URLSearchParams(req).toString()
}).then(resp => resp.json() as unknown as Token).then(token => token ? localStorage.setItem("access_token", token.access_token) : console.log("token not acquired")).catch((e) => console.log("catch error " + e + " in login"));
}
export const cookielogin = (req: LoginRequest) => {
fetch(`${baseUrl}api/token`, {
method: "POST", headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}, body: new URLSearchParams(req).toString()
}).then(resp => { createCookie(resp.headers.getSetCookie()) }).catch((e) => console.log("catch error " + e + " in login"));
}
export const logout = () => localStorage.removeItem("access_token");