Reflex/src/auth.js

406 lines
21 KiB
JavaScript
Raw Normal View History

2025-05-21 22:13:09 +07:00
import { ref, computed } from 'vue';
import api from './services/api'; // Наш API сервис
import router from './router'; // Vue Router для перенаправлений
// Реактивные переменные для состояния пользователя и токена
const user = ref(null); // Данные пользователя (или null, если не вошел)
const token = ref(localStorage.getItem('userToken') || null); // Токен из localStorage или null
// Вычисляемое свойство для проверки, аутентифицирован ли пользователь
const isAuthenticated = computed(() => !!token.value && !!user.value);
// Функция для установки токена и данных пользователя
function setUserData(userData, userToken) {
user.value = userData;
token.value = userToken;
localStorage.setItem('userToken', userToken); // Сохраняем токен в localStorage
// Устанавливаем токен в заголовки Axios для последующих запросов (если не используется интерсептор)
// Однако, наш интерсептор в api.js уже делает это, так что эта строка может быть избыточна,
// но не повредит, если интерсептор по какой-то причине не сработает сразу.
// api.defaults.headers.common['Authorization'] = `Bearer ${userToken}`;
}
// Функция для загрузки данных пользователя, если токен есть (например, при обновлении страницы)
async function fetchUser() {
if (token.value) {
2025-05-26 19:38:13 +07:00
// Проверяем, есть ли информация о блокировке в localStorage
const blockedInfoStr = localStorage.getItem('accountBlockedInfo');
if (blockedInfoStr) {
try {
const blockedInfo = JSON.parse(blockedInfoStr);
if (blockedInfo.blocked) {
console.log('[Auth] Обнаружена информация о блокировке в localStorage, выполняем выход');
// Показываем уведомление о блокировке
const notificationEvent = new CustomEvent('show-toast', {
detail: {
message: blockedInfo.message || 'Ваш аккаунт заблокирован администратором.',
type: 'error',
duration: 10000
}
});
window.dispatchEvent(notificationEvent);
// Выходим из системы
await logout();
// Перенаправляем на страницу входа с параметром блокировки
router.replace({ path: '/login', query: { blocked: 'true' } });
return;
}
} catch (error) {
console.error('[Auth] Ошибка при парсинге информации о блокировке:', error);
// Удаляем поврежденные данные
localStorage.removeItem('accountBlockedInfo');
}
}
2025-05-21 22:13:09 +07:00
try {
console.log('Пытаемся загрузить пользователя с токеном из localStorage...');
const response = await api.getMe(); // Используем наш API сервис
console.log('Ответ от /auth/me:', response);
// Проверяем структуру ответа
if (!response.data) {
throw new Error('Неверный формат ответа от сервера');
}
2025-05-25 23:36:51 +07:00
// Добавляем дополнительное логирование для отладки
console.log('Получены данные пользователя:', response.data);
console.log('Значение isAdmin в ответе:', response.data.isAdmin);
2025-05-26 19:22:43 +07:00
// Проверяем, не заблокирован ли пользователь
if (response.data.blocked) {
console.log('[Auth] Пользователь заблокирован, выполняем принудительный выход');
// Сохраняем информацию о блокировке
const blockedInfo = {
blocked: true,
message: 'Ваш аккаунт заблокирован администратором.',
reason: response.data.blockReason || 'Нарушение правил сервиса',
timestamp: new Date().toISOString()
};
localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo));
// Выходим из системы
await logout();
return;
}
// Проверяем, была ли разблокировка (если есть информация о предыдущей блокировке)
const blockedInfoStr = localStorage.getItem('accountBlockedInfo');
if (blockedInfoStr) {
console.log('[Auth] Обнаружена предыдущая блокировка, пользователь теперь разблокирован');
// Удаляем информацию о блокировке
localStorage.removeItem('accountBlockedInfo');
// Показываем уведомление о разблокировке
setTimeout(() => {
const notificationEvent = new CustomEvent('show-toast', {
detail: {
message: 'Ваш аккаунт был разблокирован. Добро пожаловать обратно!',
type: 'success',
duration: 5000
}
});
window.dispatchEvent(notificationEvent);
}, 1000);
}
2025-05-21 22:13:09 +07:00
// Сохраняем данные пользователя
user.value = response.data;
console.log('Пользователь успешно загружен:', user.value);
console.log('isAuthenticated после загрузки пользователя:', isAuthenticated.value);
2025-05-25 23:36:51 +07:00
console.log('Пользователь является администратором:', user.value.isAdmin ? 'Да' : 'Нет');
2025-05-21 22:13:09 +07:00
} catch (error) {
console.error('Не удалось загрузить пользователя по токену:', error.response ? error.response.data : error.message);
2025-05-26 19:22:43 +07:00
// Проверяем, не связана ли ошибка с блокировкой
if (error.response && error.response.status === 403 && error.response.data.message && error.response.data.message.includes('заблокирован')) {
console.log('[Auth] Пользователь заблокирован согласно ответу сервера');
// Сохраняем информацию о блокировке
const blockedInfo = {
blocked: true,
message: error.response.data.message || 'Ваш аккаунт заблокирован администратором.',
reason: error.response.data.reason || 'Нарушение правил сервиса',
timestamp: new Date().toISOString()
};
localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo));
}
2025-05-21 22:13:09 +07:00
// Если токен невалиден, очищаем его и данные пользователя
await logout(); // Вызываем logout, чтобы очистить всё
}
} else {
console.log('Токен не найден, пользователь не загружен.');
}
}
// Функция входа
async function login(credentials) {
try {
console.log('Попытка входа с учетными данными:', { email: credentials.email });
const response = await api.login(credentials);
console.log('Ответ сервера при входе:', response);
// Проверяем структуру данных в ответе
if (!response.data || !response.data.token) {
throw new Error('Неверный формат ответа от сервера: отсутствует токен');
}
// response.data должен содержать { _id, name, email, token, message }
const { token: userToken, ...userData } = response.data;
// Убедимся, что userData содержит необходимые поля
console.log('Данные пользователя для сохранения:', userData);
2025-05-26 19:26:17 +07:00
// Проверяем, была ли предыдущая блокировка и произошла ли разблокировка
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);
}
2025-05-21 22:13:09 +07:00
// Перед сохранением данных
console.log('isAuthenticated ДО входа:', isAuthenticated.value);
console.log('Данные пользователя ДО входа:', user.value);
// Сохраняем данные пользователя и токен
setUserData(userData, userToken);
// После сохранения данных, но до перенаправления
console.log('isAuthenticated ПОСЛЕ входа:', isAuthenticated.value);
console.log('Данные пользователя ПОСЛЕ входа:', user.value);
console.log('Токен ПОСЛЕ входа:', token.value);
// Принудительное обновление состояния
setTimeout(() => {
console.log('isAuthenticated после таймаута:', isAuthenticated.value);
}, 0);
router.push('/'); // Перенаправляем на главную после входа
return true;
} catch (error) {
console.error('Ошибка входа:', error.response ? error.response.data : error.message);
// Возвращаем сообщение об ошибке, чтобы отобразить в компоненте
throw error.response ? error.response.data : new Error('Ошибка сети или сервера при входе');
}
}
// Функция регистрации
async function register(userData) {
try {
const response = await api.register(userData);
// response.data должен содержать { _id, name, email, token, message }
const { token: userToken, ...newUserData } = response.data;
setUserData(newUserData, userToken);
// Обычно после регистрации мы либо сразу логиним пользователя, либо просим его войти.
// Здесь мы его сразу "залогинили", сохранив токен и данные.
router.push('/'); // Перенаправляем на главную (или на страницу подтверждения email, если бы она была)
return true;
} catch (error) {
console.error('Ошибка регистрации:', error.response ? error.response.data : error.message);
throw error.response ? error.response.data : new Error('Ошибка сети или сервера при регистрации');
}
}
// Функция выхода
async function logout() {
user.value = null;
token.value = null;
localStorage.removeItem('userToken');
// Удаляем токен из заголовков Axios (если устанавливали его напрямую)
// delete apiClient.defaults.headers.common['Authorization']; // apiClient не экспортируется из api.js напрямую для этого
// Наш интерсептор запросов в api.js перестанет добавлять токен, так как его не будет в localStorage.
router.push('/login'); // Перенаправляем на страницу входа
console.log('Пользователь вышел из системы.');
}
2025-05-26 15:52:26 +07:00
// Функция обработки события блокировки аккаунта
2025-05-26 19:16:21 +07:00
async function handleAccountBlocked(data) {
console.log('[Auth] Получено уведомление о блокировке аккаунта:', data);
2025-05-26 16:56:49 +07:00
try {
2025-05-26 19:16:21 +07:00
// Сохраняем данные о блокировке
const blockedInfo = {
2025-05-26 16:56:49 +07:00
blocked: true,
message: data?.message || 'Ваш аккаунт был заблокирован администратором.',
reason: data?.reason || 'Нарушение правил сервиса',
2025-05-26 19:16:21 +07:00
timestamp: data?.timestamp || new Date().toISOString()
2025-05-26 16:56:49 +07:00
};
2025-05-26 19:16:21 +07:00
localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo));
2025-05-26 16:56:49 +07:00
2025-05-26 19:16:21 +07:00
// Сохраняем текущие данные сессии для последующего восстановления
if (user.value && token.value) {
const sessionBackup = {
userId: user.value._id,
2025-05-26 19:16:21 +07:00
userName: user.value.name,
token: token.value,
2025-05-26 19:16:21 +07:00
timestamp: new Date().toISOString(),
lastPath: window.location.pathname
};
2025-05-26 19:16:21 +07:00
// Сохраняем резервную копию данных сессии
localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup));
2025-05-26 19:16:21 +07:00
console.log('[Auth] Сохранена резервная копия данных сессии для пользователя:', user.value.name);
} else {
console.log('[Auth] Невозможно сохранить сессию - пользователь не авторизован');
}
2025-05-26 19:30:28 +07:00
// Показываем уведомление о блокировке
const notificationEvent = new CustomEvent('show-toast', {
detail: {
message: data?.message || 'Ваш аккаунт был заблокирован администратором.',
type: 'error',
duration: 10000
}
});
window.dispatchEvent(notificationEvent);
2025-05-26 19:16:21 +07:00
// Выходим из системы
await logout();
2025-05-26 16:56:49 +07:00
2025-05-26 19:16:21 +07:00
// Перенаправляем на страницу входа с параметром блокировки
router.replace({ path: '/login', query: { blocked: 'true' } });
2025-05-26 16:56:49 +07:00
} catch (error) {
2025-05-26 19:16:21 +07:00
console.error('[Auth] Ошибка при обработке блокировки аккаунта:', error);
2025-05-26 16:56:49 +07:00
2025-05-26 19:16:21 +07:00
// В случае ошибки все равно выполняем logout и перенаправление
try {
await logout();
router.replace('/login?blocked=true');
} catch (logoutErr) {
console.error('[Auth] Ошибка при выходе после блокировки:', logoutErr);
// Принудительное перенаправление
window.location.href = '/login?blocked=true';
}
2025-05-26 16:56:49 +07:00
}
2025-05-26 15:52:26 +07:00
}
// Функция обработки события разблокировки аккаунта
async function handleAccountUnblocked(data) {
console.log('[Auth] Получено уведомление о разблокировке аккаунта:', data);
2025-05-26 15:52:26 +07:00
// Удаляем информацию о блокировке, если она была сохранена
localStorage.removeItem('accountBlockedInfo');
// Сохраняем информацию о разблокировке для отображения при следующем входе
const unblockedInfo = {
2025-05-26 15:52:26 +07:00
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] Сохраненная сессия не найдена, показываем только уведомление о разблокировке');
}
} catch (error) {
console.error('[Auth] Ошибка при восстановлении сессии после разблокировки:', error);
}
// Если мы дошли до этой точки, значит автоматическое восстановление не удалось
// или мы не нашли сохраненной сессии. Просто показываем уведомление.
console.log('[Auth] Аккаунт пользователя разблокирован без автоматического входа');
// Если пользователь уже на странице логина, добавляем параметр unblocked=true
if (window.location.pathname === '/login') {
router.replace({ path: '/login', query: { unblocked: 'true' } });
}
2025-05-26 15:52:26 +07:00
return false;
2025-05-26 15:52:26 +07:00
}
2025-05-21 22:13:09 +07:00
// Экспортируем то, что понадобится в компонентах
export function useAuth() {
return {
user,
token,
isAuthenticated,
login,
register,
logout,
fetchUser, // Эту функцию нужно будет вызвать при инициализации приложения
2025-05-26 15:52:26 +07:00
handleAccountBlocked, // Добавляем функцию обработки блокировки аккаунта
handleAccountUnblocked // Добавляем функцию обработки разблокировки аккаунта
2025-05-21 22:13:09 +07:00
};
2025-05-26 19:22:43 +07:00
}
// Экспортируем функции напрямую для использования в других частях приложения
export { handleAccountBlocked, handleAccountUnblocked };