save tokens localstorage, fix refresh sql query, added permissions
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { API_URL, setAccessToken } from "../token";
|
||||
import { API_URL, authFetch, setAccessToken } from "../token";
|
||||
|
||||
export async function login(email: string, password: string) {
|
||||
const body = new URLSearchParams({ username: email, password });
|
||||
const res = await fetch(`${API_URL}/protected/token`, {
|
||||
method: "POST",
|
||||
body,
|
||||
credentials: "include",
|
||||
body,
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) throw new Error("Неверный email или пароль");
|
||||
const data = await res.json();
|
||||
setAccessToken(data.access_token);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
return authFetch("/protected/logout");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { UserOut } from "../../types/UserTypes";
|
||||
import { authFetch } from "../token";
|
||||
|
||||
|
||||
export async function fetchCurrentUser(): Promise<UserOut> {
|
||||
const res = await authFetch("/protected/me");
|
||||
if (!res.ok) throw new Error("Не удалось получить данные пользователя");
|
||||
return res.json();
|
||||
}
|
||||
@@ -10,8 +10,58 @@ export function getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
async function requestRefresh(): Promise<{ access_token: string } | null> {
|
||||
const res = await fetch(`${API_URL}/protected/refresh`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
return res.json();
|
||||
}
|
||||
|
||||
let refreshInFlight: Promise<boolean> | null = null;
|
||||
|
||||
export function refreshAccessToken(): Promise<boolean> {
|
||||
if (refreshInFlight) return refreshInFlight;
|
||||
|
||||
refreshInFlight = (async () => {
|
||||
try {
|
||||
// refresh_token в cookie одноразовый (ротация): если другая вкладка
|
||||
// или повторный вызов уже успели обменять его на новый ровно перед
|
||||
// нашим запросом, наш "старый" токен уже отозван и сервер ответит
|
||||
// 404/401, хотя сессия на самом деле жива. Одна короткая повторная
|
||||
// попытка подхватит уже обновлённую браузером cookie и не даст
|
||||
// разлогинить валидного пользователя из-за проигранной гонки.
|
||||
let data = await requestRefresh();
|
||||
if (!data) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
data = await requestRefresh();
|
||||
}
|
||||
if (!data) {
|
||||
setAccessToken(null);
|
||||
return false;
|
||||
}
|
||||
setAccessToken(data.access_token);
|
||||
return true;
|
||||
} finally {
|
||||
refreshInFlight = null;
|
||||
}
|
||||
})();
|
||||
|
||||
return refreshInFlight;
|
||||
}
|
||||
|
||||
export async function authFetch(path: string, init: RequestInit = {}) {
|
||||
const headers = new Headers(init.headers);
|
||||
if (accessToken) headers.set("Authorization", `Bearer ${accessToken}`);
|
||||
return fetch(`${API_URL}${path}`, { ...init, headers, credentials: "include" });
|
||||
|
||||
const res = await fetch(`${API_URL}${path}`, { ...init, headers, credentials: "include" });
|
||||
if (res.status !== 401) return res;
|
||||
|
||||
const refreshed = await refreshAccessToken();
|
||||
if (!refreshed) return res;
|
||||
|
||||
const retryHeaders = new Headers(init.headers);
|
||||
if (accessToken) retryHeaders.set("Authorization", `Bearer ${accessToken}`);
|
||||
return fetch(`${API_URL}${path}`, { ...init, headers: retryHeaders, credentials: "include" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user