remake apis 0.151
All checks were successful
Build Docker / deploy (push) Successful in 44s
Build Docker / build (push) Successful in 34s

This commit is contained in:
2026-03-19 02:41:39 +03:00
parent a13b88bd32
commit 62d58e30cd
4 changed files with 101 additions and 92 deletions

View File

@@ -9,6 +9,10 @@ https://ru.homyk.space {
}
handle_path /main/* {
forward_auth backend:{$PORT} {
uri /api/verify
copy_headers Authorization
}
root * /srv/main
file_server
}

View File

@@ -1,16 +1,21 @@
from fastapi import FastAPI, Depends, HTTPException,status
from fastapi import FastAPI, Depends, HTTPException,status, Response, Cookie
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import server.backend.schema.pydantic as pydantic
import server.backend.database.db as db
from server.backend.auth.JWT import signJWT, decodeJWT
api = FastAPI(openapi_url="/api/openapi.json",docs_url="/api/docs", redoc_url="/api/redoc")
security = HTTPBearer()
security = HTTPBearer(auto_error=False)
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
token_cookie: str = Cookie(default=None)
):
token = credentials.credentials if credentials else token_cookie
if not token:
raise HTTPException(status_code=401, detail="Not authenticated")
user = decodeJWT(token)
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
raise HTTPException(status_code=401, detail="Invalid token")
return user
async def check_roles(user=Depends(get_current_user)):
user_check = await db.list_user(user["user_id"])
@@ -58,10 +63,29 @@ async def list_users(user=Depends(check_roles)):
list_of_users = await db.list_users()
return list_of_users
@api.post("/api/auth",response_model=pydantic.Token)
async def auth(code:pydantic.UserAccess):
@api.post("/api/auth")
async def auth(code: pydantic.UserAccess, response: Response):
login = await db.login_user(code)
if login == None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Forbidden")
if login is None:
raise HTTPException(status_code=401, detail="Forbidden")
token = signJWT(login)
response.set_cookie(
key="token",
value=token,
httponly=True,
secure=True,
samesite="strict"
)
return {"access_token": token, "token_type": "bearer"}
@api.get("/api/verify")
async def verify(token: str = Cookie(default=None)):
if not token:
raise HTTPException(status_code=401, detail="No token")
user = decodeJWT(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return {"status": "ok"}
@api.post("/api/logout")
async def logout(response: Response):
response.delete_cookie(key="token")
return {"status": "ok"}

View File

@@ -1,39 +1,29 @@
function getToken() {
return localStorage.getItem("token") || sessionStorage.getItem("token");
}
function tokenCheck(){
const token = getToken();
if (token) {
window.location.href = "https://ru.homyk.space/main/";
}
}
document.getElementById('loginForm').addEventListener('submit', async function (e) {
document.addEventListener('DOMContentLoaded', () => {
fetch('/api/verify', { credentials: 'include' })
.then(r => { if (r.ok) window.location.href = '/main/'; })
.catch(() => {});
document.getElementById('loginForm').addEventListener('submit', async function(e) {
e.preventDefault();
const password = document.getElementById('password').value;
const userData = {
password
};
const code = document.getElementById('password').value;
try {
const response = await fetch("https://ru.homyk.space/api/auth", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code: userData.password
}),
const response = await fetch('/api/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // ← чтобы браузер принял cookie
body: JSON.stringify({ code })
});
const data = await response.json(); // читаем только один раз
if (response.ok) { // сохраняем только при успехе
// в sessionstorage до перезахода в браузер(
sessionStorage.setItem("token", data.access_token);
const data = await response.json();
window.location.href = 'https://ru.homyk.space/main/';
} else { //парсинг и вывод ошибок, если есть
if (response.ok) {
window.location.href = '/main/';
} else {
if (Array.isArray(data.detail)) {
const messages = data.detail.map(e => {
const field = e.loc.filter(locPart => locPart !== 'body').join(' -> ');
const field = e.loc.filter(p => p !== 'body').join(' -> ');
return `${field}: ${e.msg}`;
});
showError(messages);
@@ -46,28 +36,29 @@ document.getElementById('loginForm').addEventListener('submit', async function (
} catch (err) {
showError(['Connection error: ' + err.message]);
}
});
});
function showError(messages){ //Добавление их на form со стилями
function showError(messages) {
let errorElem = document.getElementById('formError');
let container = document.getElementById('glass-container');
if (!errorElem){
if (!errorElem) {
errorElem = document.createElement('div');
errorElem.style.transition="3s";
errorElem.id = 'formError';
errorElem.style.color = 'red';
errorElem.style.marginTop = '20px';
errorElem.style.fontSize = '14px';
errorElem.style.fontWeight = '100';
errorElem.style.marginBottom = '20px';
errorElem.style.lineHeight="120%";
errorElem.style.height = 'auto';
const form = document.getElementById('loginForm');
form.insertAdjacentElement('afterend', errorElem);
};
errorElem.style.cssText = `
color: red;
margin-top: 20px;
margin-bottom: 20px;
font-size: 14px;
font-weight: 100;
line-height: 120%;
transition: 3s;
`;
document.getElementById('loginForm').insertAdjacentElement('afterend', errorElem);
}
errorElem.innerHTML = '';
messages.forEach(msg => {
const li = document.createElement('li');
li.style.listStyleType="none";
li.style.listStyleType = 'none';
li.textContent = msg;
errorElem.appendChild(li);
});

View File

@@ -1,29 +1,23 @@
function getToken() {
return localStorage.getItem("token") || sessionStorage.getItem("token");
}
function tokenCheck() {
const token = getToken();
if (!token) {
window.location.href = "https://ru.homyk.space";
}
}
document.addEventListener("DOMContentLoaded", () => {
tokenCheck();
document.getElementById('logoutForm').addEventListener('submit', function(e) {
// Проверка авторизации через cookie
fetch('/api/verify', { credentials: 'include' })
.then(r => { if (!r.ok) window.location.href = '/'; })
.catch(() => { window.location.href = '/'; });
// Logout — удаляем cookie на бэкенде
document.getElementById('logoutForm').addEventListener('submit', async function(e) {
e.preventDefault();
localStorage.removeItem("token");
sessionStorage.removeItem("token");
tokenCheck();
await fetch('/api/logout', {
method: 'POST',
credentials: 'include'
});
window.location.href = '/';
});
document.querySelector(".form-info").addEventListener("submit", async (e) => {
e.preventDefault();
const token = getToken();
const guestData = {
name: document.getElementById('ffname').value || "",
middlename: document.getElementById('fmname').value || "",
@@ -36,15 +30,11 @@ document.addEventListener("DOMContentLoaded", () => {
.join(', ')
};
console.log(guestData);
try {
const response = await fetch('/api/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // ← токен идёт через cookie
body: JSON.stringify(guestData)
});