поправил авторизацию
This commit is contained in:
36
auth.js
36
auth.js
@@ -91,6 +91,9 @@ class AuthService {
|
|||||||
|
|
||||||
const isValid = await bcrypt.compare(password, user.password);
|
const isValid = await bcrypt.compare(password, user.password);
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
// Обновляем last_login
|
||||||
|
db.run("UPDATE users SET last_login = datetime('now') WHERE id = ?", [user.id]);
|
||||||
|
|
||||||
// Не возвращаем пароль
|
// Не возвращаем пароль
|
||||||
const { password, ...userWithoutPassword } = user;
|
const { password, ...userWithoutPassword } = user;
|
||||||
resolve(userWithoutPassword);
|
resolve(userWithoutPassword);
|
||||||
@@ -135,7 +138,7 @@ class AuthService {
|
|||||||
const allowedGroups = process.env.ALLOWED_GROUPS ?
|
const allowedGroups = process.env.ALLOWED_GROUPS ?
|
||||||
process.env.ALLOWED_GROUPS.split(',').map(g => g.trim()) : [];
|
process.env.ALLOWED_GROUPS.split(',').map(g => g.trim()) : [];
|
||||||
|
|
||||||
const isAdmin = groups.some(group =>
|
const isAdmin = groups && groups.some(group =>
|
||||||
allowedGroups.includes(group)
|
allowedGroups.includes(group)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -151,11 +154,11 @@ class AuthService {
|
|||||||
|
|
||||||
const userData = {
|
const userData = {
|
||||||
login: username,
|
login: username,
|
||||||
name: full_name,
|
name: full_name || username,
|
||||||
email: `${username}@school25.ru`,
|
email: `${username}@school25.ru`,
|
||||||
role: role,
|
role: role,
|
||||||
auth_type: 'ldap',
|
auth_type: 'ldap',
|
||||||
groups: JSON.stringify(groups),
|
groups: groups ? JSON.stringify(groups) : '[]',
|
||||||
description: description || '',
|
description: description || '',
|
||||||
last_login: new Date().toISOString()
|
last_login: new Date().toISOString()
|
||||||
};
|
};
|
||||||
@@ -164,14 +167,26 @@ class AuthService {
|
|||||||
// Обновляем существующего пользователя
|
// Обновляем существующего пользователя
|
||||||
db.run(
|
db.run(
|
||||||
`UPDATE users SET
|
`UPDATE users SET
|
||||||
name = ?, email = ?, role = ?, groups = ?, description = ?, last_login = datetime('now')
|
name = ?, email = ?, role = ?, groups = ?, description = ?, last_login = datetime('now'),
|
||||||
|
updated_at = datetime('now')
|
||||||
WHERE id = ?`,
|
WHERE id = ?`,
|
||||||
[userData.name, userData.email, userData.role, userData.groups, userData.description, existingUser.id],
|
[userData.name, userData.email, userData.role, userData.groups, userData.description, existingUser.id],
|
||||||
function(err) {
|
function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
resolve({ ...existingUser, ...userData });
|
// Возвращаем полные данные пользователя
|
||||||
|
resolve({
|
||||||
|
id: existingUser.id,
|
||||||
|
login: userData.login,
|
||||||
|
name: userData.name,
|
||||||
|
email: userData.email,
|
||||||
|
role: userData.role,
|
||||||
|
auth_type: userData.auth_type,
|
||||||
|
groups: userData.groups,
|
||||||
|
description: userData.description,
|
||||||
|
last_login: new Date().toISOString()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -188,7 +203,14 @@ class AuthService {
|
|||||||
} else {
|
} else {
|
||||||
resolve({
|
resolve({
|
||||||
id: this.lastID,
|
id: this.lastID,
|
||||||
...userData
|
login: userData.login,
|
||||||
|
name: userData.name,
|
||||||
|
email: userData.email,
|
||||||
|
role: userData.role,
|
||||||
|
auth_type: userData.auth_type,
|
||||||
|
groups: userData.groups,
|
||||||
|
description: userData.description,
|
||||||
|
last_login: new Date().toISOString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +238,7 @@ class AuthService {
|
|||||||
|
|
||||||
getUserById(id) {
|
getUserById(id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.get("SELECT id, login, name, email, role, auth_type, groups, description FROM users WHERE id = ?", [id], (err, user) => {
|
db.get("SELECT id, login, name, email, role, auth_type, groups, description, last_login FROM users WHERE id = ?", [id], (err, user) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
141
server.js
141
server.js
@@ -21,10 +21,14 @@ app.use('/uploads', express.static(path.join(__dirname, 'data', 'uploads')));
|
|||||||
|
|
||||||
// Сессии
|
// Сессии
|
||||||
app.use(session({
|
app.use(session({
|
||||||
secret: process.env.SESSION_SECRET || 'fallback_secret',
|
secret: process.env.SESSION_SECRET || 'fallback_secret_change_in_production',
|
||||||
resave: false,
|
resave: true, // Изменено на true для лучшей поддержки LDAP
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 }
|
cookie: {
|
||||||
|
secure: false,
|
||||||
|
maxAge: 24 * 60 * 60 * 1000,
|
||||||
|
httpOnly: true
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Middleware для проверки аутентификации
|
// Middleware для проверки аутентификации
|
||||||
@@ -80,6 +84,7 @@ function checkIfOverdue(dueDate, status) {
|
|||||||
const due = new Date(dueDate);
|
const due = new Date(dueDate);
|
||||||
return due < now;
|
return due < now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция для проверки просроченных задач
|
// Функция для проверки просроченных задач
|
||||||
function checkOverdueTasks() {
|
function checkOverdueTasks() {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
@@ -111,6 +116,7 @@ function checkOverdueTasks() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== МАРШРУТЫ АУТЕНТИФИКАЦИИ ====================
|
// ==================== МАРШРУТЫ АУТЕНТИФИКАЦИИ ====================
|
||||||
|
|
||||||
app.post('/api/login', async (req, res) => {
|
app.post('/api/login', async (req, res) => {
|
||||||
@@ -123,25 +129,37 @@ app.post('/api/login', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const user = await authService.authenticate(login, password);
|
const user = await authService.authenticate(login, password);
|
||||||
if (user) {
|
if (user) {
|
||||||
req.session.user = user;
|
// Подготавливаем данные пользователя для сессии
|
||||||
|
const sessionUser = {
|
||||||
|
id: user.id,
|
||||||
|
login: user.login,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
role: user.role,
|
||||||
|
auth_type: user.auth_type,
|
||||||
|
groups: user.groups ? (typeof user.groups === 'string' ? JSON.parse(user.groups) : user.groups) : []
|
||||||
|
};
|
||||||
|
|
||||||
// Логируем успешный вход
|
// Сохраняем в сессию
|
||||||
console.log(`Успешная авторизация: ${user.name} (${user.login}) через ${user.auth_type}`);
|
req.session.user = sessionUser;
|
||||||
if (user.groups) {
|
|
||||||
console.log(`Группы пользователя: ${user.groups}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
// Явно сохраняем сессию
|
||||||
success: true,
|
req.session.save((err) => {
|
||||||
user: {
|
if (err) {
|
||||||
id: user.id,
|
console.error('Ошибка сохранения сессии:', err);
|
||||||
login: user.login,
|
return res.status(500).json({ error: 'Ошибка сохранения сессии' });
|
||||||
name: user.name,
|
|
||||||
email: user.email,
|
|
||||||
role: user.role,
|
|
||||||
auth_type: user.auth_type,
|
|
||||||
groups: user.groups ? JSON.parse(user.groups) : []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Логируем успешный вход
|
||||||
|
console.log(`Успешная авторизация: ${user.name} (${user.login}) через ${user.auth_type}`);
|
||||||
|
if (user.groups) {
|
||||||
|
console.log(`Группы пользователя: ${user.groups}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
user: sessionUser
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(`Неудачная попытка входа: ${login}`);
|
console.log(`Неудачная попытка входа: ${login}`);
|
||||||
@@ -154,13 +172,44 @@ app.post('/api/login', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/logout', (req, res) => {
|
app.post('/api/logout', (req, res) => {
|
||||||
req.session.destroy();
|
req.session.destroy((err) => {
|
||||||
res.json({ success: true });
|
if (err) {
|
||||||
|
console.error('Ошибка при выходе:', err);
|
||||||
|
return res.status(500).json({ error: 'Ошибка при выходе' });
|
||||||
|
}
|
||||||
|
res.json({ success: true });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/user', (req, res) => {
|
app.get('/api/user', (req, res) => {
|
||||||
if (req.session.user) {
|
if (req.session.user) {
|
||||||
res.json({ user: req.session.user });
|
// Обновляем данные пользователя из базы на случай изменений
|
||||||
|
authService.getUserById(req.session.user.id)
|
||||||
|
.then(user => {
|
||||||
|
if (user) {
|
||||||
|
const updatedUser = {
|
||||||
|
id: user.id,
|
||||||
|
login: user.login,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
role: user.role,
|
||||||
|
auth_type: user.auth_type,
|
||||||
|
groups: user.groups ? (typeof user.groups === 'string' ? JSON.parse(user.groups) : user.groups) : []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Обновляем сессию
|
||||||
|
req.session.user = updatedUser;
|
||||||
|
res.json({ user: updatedUser });
|
||||||
|
} else {
|
||||||
|
// Пользователь не найден в базе - разлогиниваем
|
||||||
|
req.session.destroy();
|
||||||
|
res.status(401).json({ error: 'Пользователь не найден' });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('Ошибка получения пользователя:', err);
|
||||||
|
res.status(500).json({ error: 'Ошибка сервера' });
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ error: 'Не аутентифицирован' });
|
res.status(401).json({ error: 'Не аутентифицирован' });
|
||||||
}
|
}
|
||||||
@@ -435,29 +484,29 @@ app.post('/api/tasks/:taskId/copy', requireAuth, (req, res) => {
|
|||||||
|
|
||||||
logActivity(newTaskId, createdBy, 'TASK_COPIED', `Создана копия задачи: ${newTitle}`);
|
logActivity(newTaskId, createdBy, 'TASK_COPIED', `Создана копия задачи: ${newTitle}`);
|
||||||
|
|
||||||
// Копируем файлы из оригинальной задачи
|
// Копируем файлы из оригинальной задачи
|
||||||
db.all("SELECT * FROM task_files WHERE task_id = ?", [taskId], (err, originalFiles) => {
|
db.all("SELECT * FROM task_files WHERE task_id = ?", [taskId], (err, originalFiles) => {
|
||||||
if (!err && originalFiles && originalFiles.length > 0) {
|
if (!err && originalFiles && originalFiles.length > 0) {
|
||||||
originalFiles.forEach(originalFile => {
|
originalFiles.forEach(originalFile => {
|
||||||
const originalFilePath = originalFile.file_path;
|
const originalFilePath = originalFile.file_path;
|
||||||
const newFilename = Date.now() + '-' + Math.round(Math.random() * 1E9) + path.extname(originalFile.original_name);
|
const newFilename = Date.now() + '-' + Math.round(Math.random() * 1E9) + path.extname(originalFile.original_name);
|
||||||
const userFolder = createUserTaskFolder(newTaskId, req.session.user.login);
|
const userFolder = createUserTaskFolder(newTaskId, req.session.user.login);
|
||||||
const newFilePath = path.join(userFolder, newFilename);
|
const newFilePath = path.join(userFolder, newFilename);
|
||||||
|
|
||||||
// Копируем файл
|
// Копируем файл
|
||||||
if (fs.existsSync(originalFilePath)) {
|
if (fs.existsSync(originalFilePath)) {
|
||||||
fs.copyFileSync(originalFilePath, newFilePath);
|
fs.copyFileSync(originalFilePath, newFilePath);
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)",
|
"INSERT INTO task_files (task_id, user_id, filename, original_name, file_path, file_size) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
[newTaskId, createdBy, newFilename, originalFile.original_name, newFilePath, originalFile.file_size]
|
[newTaskId, createdBy, newFilename, originalFile.original_name, newFilePath, originalFile.file_size]
|
||||||
);
|
);
|
||||||
|
|
||||||
logActivity(newTaskId, createdBy, 'FILE_COPIED', `Скопирован файл: ${originalFile.original_name}`);
|
logActivity(newTaskId, createdBy, 'FILE_COPIED', `Скопирован файл: ${originalFile.original_name}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Назначаем пользователей
|
// Назначаем пользователей
|
||||||
if (assignedUsers && assignedUsers.length > 0) {
|
if (assignedUsers && assignedUsers.length > 0) {
|
||||||
@@ -740,9 +789,6 @@ app.post('/api/tasks/:taskId/reopen', requireAuth, (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Остальные маршруты остаются без изменений...
|
|
||||||
// (Обновить сроки исполнителя, Удалить задачу, Восстановить задачу, Обновить статус, Файлы, Логи)
|
|
||||||
|
|
||||||
// Обновить сроки для конкретного исполнителя
|
// Обновить сроки для конкретного исполнителя
|
||||||
app.put('/api/tasks/:taskId/assignment/:userId', requireAuth, (req, res) => {
|
app.put('/api/tasks/:taskId/assignment/:userId', requireAuth, (req, res) => {
|
||||||
const { taskId, userId } = req.params;
|
const { taskId, userId } = req.params;
|
||||||
@@ -756,7 +802,7 @@ app.put('/api/tasks/:taskId/assignment/:userId', requireAuth, (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.session.user.role !== 'admin' && task.created_by !== currentUserId) {
|
if (req.session.user.role !== 'admin' && task.created_by !== currentUserId) {
|
||||||
return res.status(403).json({ error: 'У вас нет прав для редактирования сроков' });
|
return res.status(403).json({ error: 'У вас нет прав для редактирования сроки' });
|
||||||
}
|
}
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
@@ -1026,4 +1072,7 @@ app.listen(PORT, () => {
|
|||||||
console.log('- Логин: teacher, Пароль: teacher123');
|
console.log('- Логин: teacher, Пароль: teacher123');
|
||||||
console.log('LDAP авторизация доступна для пользователей школы');
|
console.log('LDAP авторизация доступна для пользователей школы');
|
||||||
console.log(`Разрешенные группы: ${process.env.ALLOWED_GROUPS}`);
|
console.log(`Разрешенные группы: ${process.env.ALLOWED_GROUPS}`);
|
||||||
|
|
||||||
|
// Запускаем проверку просроченных задач каждую минуту
|
||||||
|
setInterval(checkOverdueTasks, 60000);
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user