переделал токен
This commit is contained in:
@@ -171,19 +171,24 @@ frontend/
|
||||
|
||||
## API-клиент (`api.js`)
|
||||
|
||||
Все HTTP-запросы проходят через обёртку `apiFetch()`:
|
||||
Все HTTP-запросы проходят через обёртку `apiFetch()`. Access JWT читается из `localStorage` перед каждым запросом:
|
||||
|
||||
```javascript
|
||||
export async function apiFetch(endpoint, method = 'GET', body = null) {
|
||||
export async function apiFetch(endpoint, method = 'GET', body = null, retryOnUnauthorized = true) {
|
||||
const response = await fetch(endpoint, {
|
||||
method,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: body ? JSON.stringify(body) : null
|
||||
headers: getHeaders(body ? 'application/json' : null),
|
||||
credentials: 'same-origin',
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
});
|
||||
|
||||
if (response.status === 401 && retryOnUnauthorized) {
|
||||
const refreshed = await refreshAccessToken();
|
||||
if (refreshed) return apiFetch(endpoint, method, body, false);
|
||||
clearAuthState();
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data?.message || `Ошибка HTTP: ${response.status}`);
|
||||
}
|
||||
@@ -200,7 +205,7 @@ export const api = {
|
||||
};
|
||||
```
|
||||
|
||||
Токен берётся из `localStorage.getItem('token')`.
|
||||
При `401` клиент один раз вызывает `POST /api/auth/refresh`, обновляет `localStorage.token` и повторяет исходный запрос. Если refresh неуспешен, auth state очищается и пользователь возвращается на страницу входа.
|
||||
|
||||
---
|
||||
|
||||
@@ -211,11 +216,12 @@ export const api = {
|
||||
1. Пользователь вводит логин/пароль
|
||||
2. `script.js` отправляет `POST /api/auth/login`
|
||||
3. При успехе сохраняет в `localStorage`:
|
||||
- `token` — UUID-токен
|
||||
- `token` — access JWT
|
||||
- `role` — роль пользователя
|
||||
- `departmentId` — кафедра пользователя
|
||||
- `userId` — ID пользователя для личного расписания преподавателя
|
||||
4. Перенаправляет на соответствующий интерфейс:
|
||||
4. Refresh-токен сохраняется браузером как `HttpOnly` cookie и недоступен JavaScript
|
||||
5. Перенаправляет на соответствующий интерфейс:
|
||||
- `ADMIN` → `/admin/`
|
||||
- `EDUCATION_OFFICE` → `/admin/#schedule-view`
|
||||
- `DEPARTMENT` → `/admin/#department-workspace`
|
||||
@@ -230,13 +236,13 @@ export const api = {
|
||||
```javascript
|
||||
export function isAuthenticatedAsAdmin() {
|
||||
const role = localStorage.getItem('role');
|
||||
return token && role === 'ADMIN';
|
||||
return getToken() && role === 'ADMIN';
|
||||
}
|
||||
```
|
||||
|
||||
### Выход
|
||||
|
||||
Кнопка «Выйти» находится в dropdown-меню «Настройки» в footer боковой панели. Очищает `localStorage` и перенаправляет на `/`.
|
||||
Кнопка «Выйти» вызывает `POST /api/auth/logout`, затем очищает `localStorage` и перенаправляет на `/`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user