Compare commits
2 Commits
1d4567411b
...
22272dd938
Author | SHA1 | Date | |
---|---|---|---|
![]() |
22272dd938 | ||
![]() |
a80bb560db |
164
src/auth.js
164
src/auth.js
@ -98,31 +98,6 @@ async function login(credentials) {
|
||||
|
||||
if (response?.data) {
|
||||
setUserData(response.data, response.data.token);
|
||||
|
||||
// Очищаем данные о предыдущей блокировке при успешном входе
|
||||
const wasBlocked = localStorage.getItem('accountBlockedInfo');
|
||||
const sessionBackup = localStorage.getItem('blockedSessionBackup');
|
||||
|
||||
if (wasBlocked || sessionBackup) {
|
||||
console.log('[Auth] Обнаружена предыдущая блокировка, пользователь теперь может войти - значит разблокирован');
|
||||
|
||||
// Очищаем данные о блокировке
|
||||
localStorage.removeItem('accountBlockedInfo');
|
||||
localStorage.removeItem('blockedSessionBackup');
|
||||
|
||||
// Показываем уведомление о разблокировке
|
||||
setTimeout(() => {
|
||||
const notificationEvent = new CustomEvent('show-toast', {
|
||||
detail: {
|
||||
message: 'Ваш аккаунт был разблокирован. Добро пожаловать обратно!',
|
||||
type: 'success',
|
||||
duration: 5000
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(notificationEvent);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
router.push('/'); // Перенаправляем на главную после успешного входа
|
||||
return response.data;
|
||||
}
|
||||
@ -132,30 +107,10 @@ async function login(credentials) {
|
||||
// Обработка специального случая блокировки аккаунта
|
||||
if (error.response?.status === 403 && error.response?.data?.blocked) {
|
||||
const errorData = error.response.data;
|
||||
console.log('[Auth] Аккаунт заблокирован, сохраняем данные для восстановления сессии');
|
||||
console.log('[Auth] Аккаунт заблокирован:', errorData.message);
|
||||
|
||||
// Сохраняем данные о блокировке
|
||||
const blockedInfo = {
|
||||
blocked: true,
|
||||
message: errorData.message || 'Ваш аккаунт заблокирован администратором.',
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo));
|
||||
|
||||
// Сохраняем данные для восстановления сессии, если есть токен восстановления
|
||||
if (errorData.restorationToken && errorData.userId && errorData.userName) {
|
||||
const sessionBackup = {
|
||||
userId: errorData.userId,
|
||||
userName: errorData.userName,
|
||||
token: errorData.restorationToken,
|
||||
timestamp: new Date().toISOString(),
|
||||
lastPath: '/', // По умолчанию главная страница
|
||||
credentials: credentials // Сохраняем credentials для повторного входа
|
||||
};
|
||||
|
||||
localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup));
|
||||
console.log('[Auth] Сохранены данные для восстановления сессии заблокированного пользователя');
|
||||
}
|
||||
// Просто перенаправляем на страницу входа с параметром блокировки
|
||||
router.replace({ path: '/login', query: { blocked: 'true' } });
|
||||
}
|
||||
|
||||
throw error;
|
||||
@ -198,33 +153,6 @@ async function handleAccountBlocked(data) {
|
||||
console.log('[Auth] Получено уведомление о блокировке аккаунта:', data);
|
||||
|
||||
try {
|
||||
// Сохраняем данные о блокировке
|
||||
const blockedInfo = {
|
||||
blocked: true,
|
||||
message: data?.message || 'Ваш аккаунт был заблокирован администратором.',
|
||||
reason: data?.reason || 'Нарушение правил сервиса',
|
||||
timestamp: data?.timestamp || new Date().toISOString()
|
||||
};
|
||||
|
||||
localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo));
|
||||
|
||||
// Сохраняем текущие данные сессии для последующего восстановления
|
||||
if (user.value && token.value) {
|
||||
const sessionBackup = {
|
||||
userId: user.value._id,
|
||||
userName: user.value.name,
|
||||
token: token.value,
|
||||
timestamp: new Date().toISOString(),
|
||||
lastPath: window.location.pathname
|
||||
};
|
||||
|
||||
// Сохраняем резервную копию данных сессии
|
||||
localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup));
|
||||
console.log('[Auth] Сохранена резервная копия данных сессии для пользователя:', user.value.name);
|
||||
} else {
|
||||
console.log('[Auth] Невозможно сохранить сессию - пользователь не авторизован');
|
||||
}
|
||||
|
||||
// Показываем уведомление о блокировке
|
||||
const notificationEvent = new CustomEvent('show-toast', {
|
||||
detail: {
|
||||
@ -260,87 +188,23 @@ async function handleAccountBlocked(data) {
|
||||
async function handleAccountUnblocked(data) {
|
||||
console.log('[Auth] Получено уведомление о разблокировке аккаунта:', data);
|
||||
|
||||
// Удаляем информацию о блокировке, если она была сохранена
|
||||
localStorage.removeItem('accountBlockedInfo');
|
||||
|
||||
// Сохраняем информацию о разблокировке для отображения при следующем входе
|
||||
const unblockedInfo = {
|
||||
unblocked: true,
|
||||
message: data?.message || 'Ваш аккаунт был разблокирован.',
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
localStorage.setItem('accountUnblockedInfo', JSON.stringify(unblockedInfo));
|
||||
|
||||
// Проверяем, есть ли сохраненная сессия для восстановления
|
||||
try {
|
||||
const sessionBackupStr = localStorage.getItem('blockedSessionBackup');
|
||||
if (sessionBackupStr) {
|
||||
const sessionBackup = JSON.parse(sessionBackupStr);
|
||||
console.log('[Auth] Найдены данные для восстановления сессии:', sessionBackup);
|
||||
|
||||
// Проверяем, что данные актуальны (не старше 30 дней)
|
||||
const backupTime = new Date(sessionBackup.timestamp);
|
||||
const now = new Date();
|
||||
const thirtyDaysInMs = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
if (now - backupTime < thirtyDaysInMs && sessionBackup.userId && sessionBackup.token) {
|
||||
// Восстанавливаем сессию
|
||||
console.log('[Auth] Восстановление сессии пользователя после разблокировки');
|
||||
|
||||
// Устанавливаем токен в localStorage
|
||||
localStorage.setItem('userToken', sessionBackup.token);
|
||||
token.value = sessionBackup.token;
|
||||
|
||||
// Пробуем загрузить актуальные данные пользователя
|
||||
try {
|
||||
console.log('[Auth] Загрузка актуальных данных пользователя');
|
||||
await fetchUser();
|
||||
|
||||
if (user.value) {
|
||||
console.log('[Auth] Сессия успешно восстановлена, перенаправление в приложение');
|
||||
|
||||
// Показываем уведомление о восстановлении сессии
|
||||
const notificationEvent = new CustomEvent('show-toast', {
|
||||
detail: {
|
||||
message: 'Ваш аккаунт был разблокирован и сессия восстановлена.',
|
||||
type: 'success',
|
||||
duration: 5000
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(notificationEvent);
|
||||
|
||||
// Удаляем сохраненные данные сессии
|
||||
localStorage.removeItem('blockedSessionBackup');
|
||||
|
||||
// Перенаправление на главную страницу или на последнюю просмотренную страницу
|
||||
window.location.href = sessionBackup.lastPath || '/';
|
||||
return true;
|
||||
}
|
||||
} catch (fetchError) {
|
||||
console.error('[Auth] Ошибка при загрузке данных пользователя:', fetchError);
|
||||
}
|
||||
} else {
|
||||
console.log('[Auth] Сохраненная сессия устарела или неполная, будет выполнен обычный вход');
|
||||
// Удаляем устаревшие данные сессии
|
||||
localStorage.removeItem('blockedSessionBackup');
|
||||
}
|
||||
} else {
|
||||
console.log('[Auth] Сохраненная сессия не найдена, показываем только уведомление о разблокировке');
|
||||
// Показываем уведомление о разблокировке
|
||||
const notificationEvent = new CustomEvent('show-toast', {
|
||||
detail: {
|
||||
message: data?.message || 'Ваш аккаунт был разблокирован администратором.',
|
||||
type: 'success',
|
||||
duration: 5000
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Auth] Ошибка при восстановлении сессии после разблокировки:', error);
|
||||
}
|
||||
|
||||
// Если мы дошли до этой точки, значит автоматическое восстановление не удалось
|
||||
// или мы не нашли сохраненной сессии. Просто показываем уведомление.
|
||||
console.log('[Auth] Аккаунт пользователя разблокирован без автоматического входа');
|
||||
});
|
||||
window.dispatchEvent(notificationEvent);
|
||||
|
||||
// Если пользователь уже на странице логина, добавляем параметр unblocked=true
|
||||
if (window.location.pathname === '/login') {
|
||||
router.replace({ path: '/login', query: { unblocked: 'true' } });
|
||||
} else {
|
||||
// Перенаправляем на страницу входа с параметром разблокировки
|
||||
router.replace({ path: '/login', query: { unblocked: 'true' } });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Экспортируем то, что понадобится в компонентах
|
||||
|
@ -1,76 +1,22 @@
|
||||
import axios from 'axios';
|
||||
import { useAuth } from '../auth'; // Импортируем функцию авторизации
|
||||
import { isAccountBlocked } from './socketService'; // Импортируем проверку блокировки из socketService
|
||||
|
||||
// Создаем экземпляр Axios с базовым URL нашего API
|
||||
// Настраиваем базовый URL в зависимости от окружения
|
||||
|
||||
// Храним токены отмены запросов для возможности отмены при блокировке
|
||||
const cancelTokenSources = new Map();
|
||||
|
||||
// Проверка блокировки аккаунта из localStorage
|
||||
const checkAccountBlockStatus = () => {
|
||||
try {
|
||||
const blockedInfo = localStorage.getItem('accountBlockedInfo');
|
||||
if (blockedInfo) {
|
||||
const blockedData = JSON.parse(blockedInfo);
|
||||
if (blockedData?.blocked === true) {
|
||||
console.warn('[API] Обнаружен заблокированный аккаунт, запросы невозможны');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем также флаг из socketService
|
||||
if (isAccountBlocked && isAccountBlocked()) {
|
||||
console.warn('[API] Аккаунт заблокирован согласно socketService, запросы невозможны');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
console.error('[API] Ошибка при проверке статуса блокировки:', e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Определяем базовый URL в зависимости от среды выполнения
|
||||
const getBaseUrl = () => {
|
||||
// Всегда используем относительный путь /api.
|
||||
// В режиме разработки Vite dev server будет проксировать эти запросы согласно настройке server.proxy в vite.config.js.
|
||||
// В продакшене предполагается, что веб-сервер (например, Nginx) настроен аналогично для обработки /api.
|
||||
// return '/api';
|
||||
return import.meta.env.VITE_API_BASE_URL; // Используем переменную окружения Vite
|
||||
};
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: getBaseUrl(),
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// (Опционально, но очень полезно) Перехватчик для добавления JWT токена к запросам
|
||||
// Храним токены отмены запросов для возможности отмены при блокировке
|
||||
const cancelTokenSources = new Map();
|
||||
|
||||
// Интерсептор запросов - добавляет токен авторизации к каждому запросу
|
||||
apiClient.interceptors.request.use(
|
||||
(config) => {
|
||||
// Проверяем, заблокирован ли аккаунт, ПЕРЕД выполнением запроса
|
||||
if (checkAccountBlockStatus()) {
|
||||
// Если аккаунт заблокирован, отменяем запрос
|
||||
const source = axios.CancelToken.source();
|
||||
config.cancelToken = source.token;
|
||||
source.cancel('Запрос отменен из-за блокировки аккаунта');
|
||||
console.error('[API] Запрос отменен из-за блокировки аккаунта:', config.url);
|
||||
|
||||
// Перенаправляем на страницу логина, если пользователь пытается выполнять запросы
|
||||
setTimeout(() => {
|
||||
if (window.location.pathname !== '/login') {
|
||||
window.location.href = '/login?blocked=true';
|
||||
}
|
||||
}, 0);
|
||||
|
||||
return Promise.reject(new Error('Аккаунт заблокирован'));
|
||||
}
|
||||
|
||||
const token = localStorage.getItem('userToken'); // Предполагаем, что токен хранится в localStorage
|
||||
const token = localStorage.getItem('userToken');
|
||||
if (token) {
|
||||
console.log('[API] Добавление токена к запросу:', config.url);
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
@ -94,7 +40,7 @@ apiClient.interceptors.request.use(
|
||||
}
|
||||
);
|
||||
|
||||
// (Опционально) Перехватчик ответов для обработки глобальных ошибок, например, 401
|
||||
// Интерсептор ответов для обработки глобальных ошибок
|
||||
apiClient.interceptors.response.use(
|
||||
(response) => {
|
||||
// Удаляем источник токена отмены после успешного ответа
|
||||
@ -134,7 +80,6 @@ apiClient.interceptors.response.use(
|
||||
console.error('[API] Неавторизованный запрос (401):', error.config.url);
|
||||
|
||||
// Обходим замыкание, чтобы избежать проблем с импортом
|
||||
// При использовании такого подхода, logout будет вызван после текущего цикла выполнения JS
|
||||
setTimeout(() => {
|
||||
const { logout } = useAuth();
|
||||
logout();
|
||||
@ -165,10 +110,9 @@ const setAuthToken = (token) => {
|
||||
|
||||
// Экспортируем функции для конкретных эндпоинтов
|
||||
export default {
|
||||
// Добавляем новые утилитарные методы
|
||||
// Утилитарные методы
|
||||
cancelActiveRequests,
|
||||
setAuthToken,
|
||||
checkAccountBlockStatus,
|
||||
|
||||
register(userData) {
|
||||
return apiClient.post('/auth/register', userData);
|
||||
@ -176,7 +120,7 @@ export default {
|
||||
login(credentials) {
|
||||
return apiClient.post('/auth/login', credentials);
|
||||
},
|
||||
getMe() { // Для получения данных пользователя
|
||||
getMe() {
|
||||
return apiClient.get('/auth/me');
|
||||
},
|
||||
updateUserProfile(profileData) {
|
||||
@ -195,11 +139,10 @@ export default {
|
||||
uploadUserProfilePhoto(formData) {
|
||||
return apiClient.post('/users/profile/photo', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data', // Важно для FormData
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
},
|
||||
// Новые методы для управления фотографиями
|
||||
setMainPhoto(photoId) {
|
||||
return apiClient.put(`/users/profile/photo/${photoId}/set-main`);
|
||||
},
|
||||
@ -207,10 +150,10 @@ export default {
|
||||
return apiClient.delete(`/users/profile/photo/${photoId}`);
|
||||
},
|
||||
getUserConversations() {
|
||||
return apiClient.get('/conversations'); // GET /api/conversations
|
||||
return apiClient.get('/conversations');
|
||||
},
|
||||
getMessagesForConversation(conversationId) {
|
||||
return apiClient.get(`/conversations/${conversationId}/messages`); // GET /api/conversations/:id/messages
|
||||
return apiClient.get(`/conversations/${conversationId}/messages`);
|
||||
},
|
||||
deleteMessage(conversationId, messageId) {
|
||||
return apiClient.delete(`/conversations/${conversationId}/messages/${messageId}`);
|
||||
|
@ -77,29 +77,11 @@ export const connectSocket = () => {
|
||||
// Сбрасываем флаг блокировки
|
||||
wasAccountBlocked = false;
|
||||
|
||||
// Сохраняем информацию о разблокировке для последующего восстановления сессии
|
||||
const unblockData = {
|
||||
unblocked: true,
|
||||
message: data?.message || 'Ваш аккаунт был разблокирован администратором.',
|
||||
timestamp: data?.timestamp || new Date().toISOString(),
|
||||
userId: data?.userId || user.value?._id,
|
||||
unblockType: data?.unblockType || 'server_notification',
|
||||
canRestoreSession: data?.unblockData?.canRestoreSession || true
|
||||
};
|
||||
|
||||
// Сохраняем данные разблокировки в localStorage
|
||||
try {
|
||||
localStorage.setItem('accountUnblockedInfo', JSON.stringify(unblockData));
|
||||
console.log('[SocketService] Информация о разблокировке сохранена в localStorage');
|
||||
} catch (storageError) {
|
||||
console.error('[SocketService] Ошибка при сохранении информации о разблокировке:', storageError);
|
||||
}
|
||||
|
||||
// Вызываем обработчик разблокировки
|
||||
if (typeof handleAccountUnblocked === 'function') {
|
||||
try {
|
||||
console.log('[SocketService] Вызов обработчика разблокировки аккаунта');
|
||||
handleAccountUnblocked(unblockData);
|
||||
handleAccountUnblocked(data);
|
||||
} catch (error) {
|
||||
console.error('[SocketService] Ошибка при обработке разблокировки аккаунта:', error);
|
||||
|
||||
@ -130,28 +112,23 @@ export const connectSocket = () => {
|
||||
console.log('[SocketService] Это уведомление относится к текущему пользователю, сбрасываем флаг блокировки');
|
||||
wasAccountBlocked = false;
|
||||
|
||||
// Проверяем наличие сохраненных данных о блокировке
|
||||
const blockedInfoStr = localStorage.getItem('accountBlockedInfo');
|
||||
if (blockedInfoStr) {
|
||||
console.log('[SocketService] Найдена информация о блокировке, вызываем обработчик разблокировки');
|
||||
|
||||
if (typeof handleAccountUnblocked === 'function') {
|
||||
try {
|
||||
// Создаем объект с данными разблокировки
|
||||
const unblockData = {
|
||||
message: 'Ваш аккаунт был разблокирован администратором.',
|
||||
timestamp: data.timestamp,
|
||||
userId: data.userId,
|
||||
unblockType: 'global_notification',
|
||||
unblockData: {
|
||||
canRestoreSession: true
|
||||
}
|
||||
};
|
||||
|
||||
handleAccountUnblocked(unblockData);
|
||||
} catch (error) {
|
||||
console.error('[SocketService] Ошибка при обработке глобальной разблокировки:', error);
|
||||
}
|
||||
// Вызываем обработчик разблокировки
|
||||
if (typeof handleAccountUnblocked === 'function') {
|
||||
try {
|
||||
// Создаем объект с данными разблокировки
|
||||
const unblockData = {
|
||||
message: 'Ваш аккаунт был разблокирован администратором.',
|
||||
timestamp: data.timestamp,
|
||||
userId: data.userId,
|
||||
unblockType: 'global_notification',
|
||||
unblockData: {
|
||||
canRestoreSession: true
|
||||
}
|
||||
};
|
||||
|
||||
handleAccountUnblocked(unblockData);
|
||||
} catch (error) {
|
||||
console.error('[SocketService] Ошибка при обработке глобальной разблокировки:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,32 +135,11 @@ const enableScroll = () => {
|
||||
onMounted(async () => {
|
||||
preventScroll(); // Блокируем прокрутку при монтировании компонента
|
||||
|
||||
// Проверяем, есть ли информация о блокировке в localStorage
|
||||
const storedBlockInfo = localStorage.getItem('accountBlockedInfo');
|
||||
if (storedBlockInfo) {
|
||||
try {
|
||||
const parsedInfo = JSON.parse(storedBlockInfo);
|
||||
blockedInfo.value = parsedInfo;
|
||||
|
||||
// Удаляем дублирующее сообщение об ошибке, так как эта информация уже
|
||||
// отображается в блоке blocked-account-message выше кнопки "Войти"
|
||||
} catch (e) {
|
||||
console.error('Ошибка при парсинге информации о блокировке:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем наличие информации о разблокировке только для отображения уведомления
|
||||
const unblockedInfoStr = localStorage.getItem('accountUnblockedInfo');
|
||||
if (unblockedInfoStr) {
|
||||
try {
|
||||
const unblockedInfo = JSON.parse(unblockedInfoStr);
|
||||
// Отображаем уведомление о разблокировке
|
||||
errorMessage.value = unblockedInfo.message || 'Ваш аккаунт был разблокирован. Пожалуйста, войдите в систему.';
|
||||
// Удаляем информацию о разблокировке, чтобы сообщение не появлялось повторно
|
||||
localStorage.removeItem('accountUnblockedInfo');
|
||||
} catch (e) {
|
||||
console.error('[LoginView] Ошибка при парсинге информации о разблокировке:', e);
|
||||
}
|
||||
// Проверяем query параметры для отображения сообщений
|
||||
if (route.query.blocked === 'true') {
|
||||
errorMessage.value = 'Ваш аккаунт заблокирован администратором.';
|
||||
} else if (route.query.unblocked === 'true') {
|
||||
errorMessage.value = 'Ваш аккаунт был разблокирован. Пожалуйста, войдите в систему.';
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user