153 lines
8.8 KiB
JavaScript
153 lines
8.8 KiB
JavaScript
// /server/auth/authService.js
|
||
const bcrypt = require('bcryptjs'); // Для хеширования паролей
|
||
const jwt = require('jsonwebtoken'); // <<< ДОБАВЛЕНО
|
||
const db = require('../core/db'); // Путь к вашему модулю для работы с базой данных
|
||
|
||
const SALT_ROUNDS = 10; // Количество раундов для генерации соли bcrypt
|
||
|
||
/**
|
||
* Регистрирует нового пользователя и генерирует JWT.
|
||
* @param {string} username - Имя пользователя.
|
||
* @param {string} password - Пароль пользователя.
|
||
* @returns {Promise<object>} Объект с результатом: { success: boolean, message: string, token?: string, userId?: number, username?: string }
|
||
*/
|
||
async function registerUser(username, password) {
|
||
console.log(`[AuthService DEBUG] registerUser called with username: "${username}"`);
|
||
|
||
if (!username || !password) {
|
||
console.warn('[AuthService DEBUG] Validation failed: Username or password empty.');
|
||
return { success: false, message: 'Имя пользователя и пароль не могут быть пустыми.' };
|
||
}
|
||
if (password.length < 6) {
|
||
console.warn(`[AuthService DEBUG] Validation failed for "${username}": Password too short.`);
|
||
return { success: false, message: 'Пароль должен содержать не менее 6 символов.' };
|
||
}
|
||
|
||
try {
|
||
// Этап A: Проверка существующего пользователя
|
||
console.log(`[AuthService DEBUG] Stage A: Checking if user "${username}" exists...`);
|
||
// Предполагаем, что db.query возвращает массив, где первый элемент - это массив строк (результатов)
|
||
const [existingUsers] = await db.query('SELECT id FROM users WHERE username = ?', [username]);
|
||
console.log(`[AuthService DEBUG] Stage A: existingUsers query result length: ${existingUsers.length}`);
|
||
|
||
if (existingUsers.length > 0) {
|
||
console.warn(`[AuthService DEBUG] Registration declined for "${username}": Username already taken.`);
|
||
return { success: false, message: 'Это имя пользователя уже занято.' };
|
||
}
|
||
console.log(`[AuthService DEBUG] Stage A: Username "${username}" is available.`);
|
||
|
||
// Этап B: Хеширование пароля
|
||
console.log(`[AuthService DEBUG] Stage B: Hashing password for user "${username}"...`);
|
||
const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
|
||
console.log(`[AuthService DEBUG] Stage B: Password for "${username}" hashed successfully.`);
|
||
|
||
// Этап C: Сохранение пользователя в БД
|
||
console.log(`[AuthService DEBUG] Stage C: Attempting to insert user "${username}" into DB...`);
|
||
// Предполагаем, что db.query для INSERT возвращает объект результата с insertId
|
||
const [result] = await db.query(
|
||
'INSERT INTO users (username, password_hash) VALUES (?, ?)',
|
||
[username, hashedPassword]
|
||
);
|
||
console.log(`[AuthService DEBUG] Stage C: DB insert result for "${username}":`, result);
|
||
|
||
if (result && result.insertId) {
|
||
const userId = result.insertId;
|
||
// Генерируем JWT токен
|
||
const tokenPayload = { userId: userId, username: username };
|
||
const token = jwt.sign(
|
||
tokenPayload,
|
||
process.env.JWT_SECRET, // Используем секрет из .env
|
||
{ expiresIn: process.env.JWT_EXPIRES_IN || '1h' } // Используем срок из .env или по умолчанию 1 час
|
||
);
|
||
|
||
console.log(`[AuthService] Пользователь "${username}" успешно зарегистрирован с ID: ${userId}. Токен выдан.`);
|
||
return {
|
||
success: true,
|
||
message: 'Регистрация прошла успешно! Вы вошли в систему.',
|
||
token: token, // <<< ВОЗВРАЩАЕМ ТОКЕН
|
||
userId: userId,
|
||
username: username // Возвращаем и имя пользователя
|
||
};
|
||
} else {
|
||
console.error(`[AuthService] Ошибка БД при регистрации пользователя "${username}": Запись не была вставлена или insertId отсутствует. Result:`, result);
|
||
return { success: false, message: 'Ошибка сервера при регистрации (данные не сохранены). Попробуйте позже.' };
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error(`[AuthService] КРИТИЧЕСКАЯ ОШИБКА (catch block) при регистрации пользователя "${username}":`, error);
|
||
if (error.sqlMessage) {
|
||
console.error(`[AuthService] MySQL Error Message: ${error.sqlMessage}`);
|
||
console.error(`[AuthService] MySQL Error Code: ${error.code}`);
|
||
console.error(`[AuthService] MySQL Errno: ${error.errno}`);
|
||
}
|
||
return { success: false, message: 'Внутренняя ошибка сервера при регистрации.' };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Выполняет вход пользователя и генерирует JWT.
|
||
* @param {string} username - Имя пользователя.
|
||
* @param {string} password - Пароль пользователя.
|
||
* @returns {Promise<object>} Объект с результатом: { success: boolean, message: string, token?: string, userId?: number, username?: string }
|
||
*/
|
||
async function loginUser(username, password) {
|
||
console.log(`[AuthService DEBUG] loginUser called with username: "${username}"`);
|
||
|
||
if (!username || !password) {
|
||
console.warn('[AuthService DEBUG] Login validation failed: Username or password empty.');
|
||
return { success: false, message: 'Имя пользователя и пароль не могут быть пустыми.' };
|
||
}
|
||
|
||
try {
|
||
console.log(`[AuthService DEBUG] Searching for user "${username}" in DB...`);
|
||
const [users] = await db.query('SELECT id, username, password_hash FROM users WHERE username = ?', [username]);
|
||
console.log(`[AuthService DEBUG] DB query result for user "${username}" (length): ${users.length}`);
|
||
|
||
if (users.length === 0) {
|
||
console.warn(`[AuthService DEBUG] Login failed: User "${username}" not found.`);
|
||
return { success: false, message: 'Неверное имя пользователя или пароль.' };
|
||
}
|
||
|
||
const user = users[0];
|
||
console.log(`[AuthService DEBUG] User "${username}" found. ID: ${user.id}. Comparing password...`);
|
||
|
||
const passwordMatch = await bcrypt.compare(password, user.password_hash);
|
||
console.log(`[AuthService DEBUG] Password comparison result for "${username}": ${passwordMatch}`);
|
||
|
||
if (passwordMatch) {
|
||
// Генерируем JWT токен
|
||
const tokenPayload = { userId: user.id, username: user.username };
|
||
const token = jwt.sign(
|
||
tokenPayload,
|
||
process.env.JWT_SECRET, // Используем секрет из .env
|
||
{ expiresIn: process.env.JWT_EXPIRES_IN || '1h' } // Используем срок из .env или по умолчанию 1 час
|
||
);
|
||
|
||
console.log(`[AuthService] Пользователь "${user.username}" (ID: ${user.id}) успешно вошел в систему. Токен выдан.`);
|
||
return {
|
||
success: true,
|
||
message: 'Вход выполнен успешно!',
|
||
token: token, // <<< ВОЗВРАЩАЕМ ТОКЕН
|
||
userId: user.id,
|
||
username: user.username // Возвращаем имя пользователя
|
||
};
|
||
} else {
|
||
console.warn(`[AuthService DEBUG] Login failed for user "${user.username}": Incorrect password.`);
|
||
return { success: false, message: 'Неверное имя пользователя или пароль.' };
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error(`[AuthService] КРИТИЧЕСКАЯ ОШИБКА (catch block) при входе пользователя "${username}":`, error);
|
||
if (error.sqlMessage) {
|
||
console.error(`[AuthService] MySQL Error Message: ${error.sqlMessage}`);
|
||
console.error(`[AuthService] MySQL Error Code: ${error.code}`);
|
||
console.error(`[AuthService] MySQL Errno: ${error.errno}`);
|
||
}
|
||
return { success: false, message: 'Внутренняя ошибка сервера при входе.' };
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
registerUser,
|
||
loginUser
|
||
}; |