Описание изменений
This commit is contained in:
@@ -1,130 +1,132 @@
|
||||
const { createError } = require('./errorHandler');
|
||||
const authService = require('../services/auth-service');
|
||||
const logger = require('../utils/logger');
|
||||
const { getUserInfo } = require('../utils/access-check');
|
||||
const { USER_ROLES } = require('../utils/constants');
|
||||
const db = require('../db');
|
||||
|
||||
// Добавьте в начало файла
|
||||
const isMiddleware = true;
|
||||
|
||||
// Middleware для проверки роли
|
||||
const requireRole = (allowedRoles) => async (req, res, next) => {
|
||||
if (!req.session || !req.session.authenticated || !req.session.userId) {
|
||||
return res.status(401).json({ error: 'Требуется аутентификация' });
|
||||
/**
|
||||
* Middleware для проверки аутентификации
|
||||
*/
|
||||
function requireAuth(req, res, next) {
|
||||
console.log('Session in requireAuth:', req.session);
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
return next(createError(401, 'Требуется аутентификация'));
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware для проверки прав администратора
|
||||
*/
|
||||
async function requireAdmin(req, res, next) {
|
||||
try {
|
||||
// Получение информации о пользователе
|
||||
const userInfo = await getUserInfo(req.session.userId);
|
||||
|
||||
if (!userInfo) {
|
||||
return res.status(401).json({ error: 'Пользователь не найден' });
|
||||
}
|
||||
|
||||
// Проверка роли
|
||||
if (!allowedRoles.includes(userInfo.role)) {
|
||||
return res.status(403).json({ error: 'Недостаточно прав' });
|
||||
}
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.error('Error checking user role:', error);
|
||||
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
|
||||
}
|
||||
};
|
||||
|
||||
// Проверка роли пользователя
|
||||
const checkRole = async (req, res, next) => {
|
||||
try {
|
||||
// Если функция вызвана как middleware
|
||||
const isMiddleware = typeof next === 'function';
|
||||
|
||||
if (!req.session.authenticated) {
|
||||
return isMiddleware ? res.status(401).json({ error: 'Не авторизован' }) : false;
|
||||
// Проверка аутентификации
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
return next(createError('Требуется аутентификация', 401));
|
||||
}
|
||||
|
||||
// Если роль администратора уже проверена в сессии
|
||||
if (req.session.isAdmin === true) {
|
||||
return isMiddleware ? next() : true;
|
||||
// Проверка через сессию
|
||||
if (req.session.isAdmin) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const db = require('../db');
|
||||
|
||||
// Проверка наличия токенов доступа в смарт-контракте
|
||||
// Проверка через кошелек
|
||||
if (req.session.address) {
|
||||
const address = req.session.address.toLowerCase();
|
||||
|
||||
// Проверка в базе данных
|
||||
const userRole = await db.query(
|
||||
'SELECT r.name FROM users u JOIN roles r ON u.role_id = r.id WHERE LOWER(u.address) = $1',
|
||||
[address]
|
||||
);
|
||||
|
||||
if (userRole.rows.length > 0 && userRole.rows[0].name === 'admin') {
|
||||
const isAdmin = await authService.checkAdminToken(req.session.address);
|
||||
if (isAdmin) {
|
||||
// Обновляем сессию
|
||||
req.session.isAdmin = true;
|
||||
return isMiddleware ? next() : true;
|
||||
}
|
||||
|
||||
// Проверка токенов в смарт-контракте через сервис
|
||||
const { ethers } = require('ethers');
|
||||
const provider = new ethers.JsonRpcProvider(process.env.PROVIDER_URL);
|
||||
const accessTokenABI = require('../artifacts/contracts/AccessToken.sol/AccessToken.json').abi;
|
||||
const accessTokenContract = new ethers.Contract(
|
||||
process.env.ACCESS_TOKEN_ADDRESS,
|
||||
accessTokenABI,
|
||||
provider
|
||||
);
|
||||
|
||||
try {
|
||||
const hasAdminRole = await accessTokenContract.hasRole(
|
||||
ethers.keccak256(ethers.toUtf8Bytes('ADMIN_ROLE')),
|
||||
address
|
||||
);
|
||||
|
||||
if (hasAdminRole) {
|
||||
// Обновляем роль в базе данных
|
||||
await db.query(
|
||||
'UPDATE users SET role_id = (SELECT id FROM roles WHERE name = $1) WHERE LOWER(address) = $2',
|
||||
['admin', address]
|
||||
);
|
||||
req.session.isAdmin = true;
|
||||
return isMiddleware ? next() : true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при проверке роли в контракте:', error);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
// Если пользователь не администратор
|
||||
req.session.isAdmin = false;
|
||||
return isMiddleware ? res.status(403).json({ error: 'Недостаточно прав' }) : false;
|
||||
// Проверка через ID пользователя
|
||||
if (req.session.userId) {
|
||||
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
|
||||
if (userResult.rows.length > 0 && userResult.rows[0].role === USER_ROLES.ADMIN) {
|
||||
// Обновляем сессию
|
||||
req.session.isAdmin = true;
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
// Если ни одна проверка не прошла
|
||||
return next(createError('Доступ запрещен', 403));
|
||||
} catch (error) {
|
||||
console.error('Ошибка при проверке роли:', error);
|
||||
return isMiddleware ? res.status(500).json({ error: 'Внутренняя ошибка сервера' }) : false;
|
||||
logger.error(`Error in requireAdmin middleware: ${error.message}`);
|
||||
return next(createError('Внутренняя ошибка сервера', 500));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Middleware для проверки аутентификации
|
||||
const requireAuth = (req, res, next) => {
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
return res.status(401).json({ error: 'Требуется аутентификация' });
|
||||
}
|
||||
next();
|
||||
};
|
||||
/**
|
||||
* Middleware для проверки определенной роли
|
||||
* @param {string} role - Требуемая роль
|
||||
*/
|
||||
function requireRole(role) {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// Проверка аутентификации
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
return next(createError('Требуется аутентификация', 401));
|
||||
}
|
||||
|
||||
// Middleware для проверки прав администратора
|
||||
const requireAdmin = (req, res, next) => {
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
return res.status(401).json({ error: 'Требуется аутентификация' });
|
||||
}
|
||||
|
||||
if (!req.session.isAdmin) {
|
||||
return res.status(403).json({ error: 'Требуются права администратора' });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
// Для администраторов разрешаем все
|
||||
if (req.session.isAdmin) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Проверка через ID пользователя
|
||||
if (req.session.userId) {
|
||||
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
|
||||
if (userResult.rows.length > 0 && userResult.rows[0].role === role) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
// Если проверка не прошла
|
||||
return next(createError('Доступ запрещен', 403));
|
||||
} catch (error) {
|
||||
logger.error(`Error in requireRole middleware: ${error.message}`);
|
||||
return next(createError('Внутренняя ошибка сервера', 500));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет роль пользователя
|
||||
* @param {string} role - Роль для проверки
|
||||
*/
|
||||
function checkRole(role) {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// Если пользователь не аутентифицирован, просто продолжаем
|
||||
if (!req.session || !req.session.authenticated) {
|
||||
req.hasRole = false;
|
||||
return next();
|
||||
}
|
||||
|
||||
// Проверка через ID пользователя
|
||||
if (req.session.userId) {
|
||||
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
|
||||
if (userResult.rows.length > 0 && userResult.rows[0].role === role) {
|
||||
req.hasRole = true;
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
req.hasRole = false;
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.error(`Error in checkRole middleware: ${error.message}`);
|
||||
req.hasRole = false;
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
requireRole,
|
||||
requireAuth,
|
||||
requireAdmin,
|
||||
checkRole,
|
||||
requireRole,
|
||||
checkRole
|
||||
};
|
||||
|
||||
71
backend/middleware/errorHandler.js
Normal file
71
backend/middleware/errorHandler.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const logger = require('../utils/logger');
|
||||
const { ERROR_CODES } = require('../utils/constants');
|
||||
|
||||
/**
|
||||
* Middleware для обработки ошибок
|
||||
*/
|
||||
function errorHandler(err, req, res, next) {
|
||||
// Логируем ошибку
|
||||
logger.error(`Error: ${err.message}`, {
|
||||
stack: err.stack,
|
||||
url: req.originalUrl,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
userId: req.session?.userId
|
||||
});
|
||||
|
||||
// Определяем тип ошибки
|
||||
let statusCode = 500;
|
||||
let errorCode = ERROR_CODES.INTERNAL_ERROR;
|
||||
let errorMessage = 'Внутренняя ошибка сервера';
|
||||
|
||||
// Обрабатываем разные типы ошибок
|
||||
if (err.name === 'UnauthorizedError' || err.status === 401) {
|
||||
statusCode = 401;
|
||||
errorCode = ERROR_CODES.UNAUTHORIZED;
|
||||
errorMessage = 'Требуется аутентификация';
|
||||
} else if (err.status === 403) {
|
||||
statusCode = 403;
|
||||
errorCode = ERROR_CODES.FORBIDDEN;
|
||||
errorMessage = 'Доступ запрещен';
|
||||
} else if (err.status === 404) {
|
||||
statusCode = 404;
|
||||
errorCode = ERROR_CODES.NOT_FOUND;
|
||||
errorMessage = 'Ресурс не найден';
|
||||
} else if (err.status === 400) {
|
||||
statusCode = 400;
|
||||
errorCode = ERROR_CODES.BAD_REQUEST;
|
||||
errorMessage = err.message || 'Некорректный запрос';
|
||||
}
|
||||
|
||||
// В режиме разработки возвращаем стек ошибки
|
||||
const devError = process.env.NODE_ENV === 'development'
|
||||
? { stack: err.stack }
|
||||
: {};
|
||||
|
||||
// Отправляем ответ клиенту
|
||||
res.status(statusCode).json({
|
||||
error: {
|
||||
code: errorCode,
|
||||
message: errorMessage,
|
||||
...devError
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Функция для создания ошибок с определенным статусом
|
||||
* @param {string} message - Сообщение об ошибке
|
||||
* @param {number} status - HTTP-статус ошибки
|
||||
* @returns {Error} - Объект ошибки
|
||||
*/
|
||||
function createError(message, status) {
|
||||
const error = new Error(message);
|
||||
error.status = status;
|
||||
return error;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
errorHandler,
|
||||
createError
|
||||
};
|
||||
56
backend/middleware/errorMiddleware.js
Normal file
56
backend/middleware/errorMiddleware.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const logger = require('../utils/logger');
|
||||
const { ERROR_CODES } = require('../utils/constants');
|
||||
|
||||
/**
|
||||
* Middleware для обработки ошибок
|
||||
*/
|
||||
function errorMiddleware(err, req, res, next) {
|
||||
// Логируем ошибку
|
||||
logger.error(`Error: ${err.message}`, {
|
||||
stack: err.stack,
|
||||
url: req.originalUrl,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
userId: req.session?.userId
|
||||
});
|
||||
|
||||
// Определяем тип ошибки
|
||||
let statusCode = 500;
|
||||
let errorCode = ERROR_CODES.INTERNAL_ERROR;
|
||||
let errorMessage = 'Внутренняя ошибка сервера';
|
||||
|
||||
// Обрабатываем разные типы ошибок
|
||||
if (err.name === 'UnauthorizedError' || err.status === 401) {
|
||||
statusCode = 401;
|
||||
errorCode = ERROR_CODES.UNAUTHORIZED;
|
||||
errorMessage = 'Требуется аутентификация';
|
||||
} else if (err.status === 403) {
|
||||
statusCode = 403;
|
||||
errorCode = ERROR_CODES.FORBIDDEN;
|
||||
errorMessage = 'Доступ запрещен';
|
||||
} else if (err.status === 404) {
|
||||
statusCode = 404;
|
||||
errorCode = ERROR_CODES.NOT_FOUND;
|
||||
errorMessage = 'Ресурс не найден';
|
||||
} else if (err.status === 400) {
|
||||
statusCode = 400;
|
||||
errorCode = ERROR_CODES.BAD_REQUEST;
|
||||
errorMessage = err.message || 'Некорректный запрос';
|
||||
}
|
||||
|
||||
// В режиме разработки возвращаем стек ошибки
|
||||
const devError = process.env.NODE_ENV === 'development'
|
||||
? { stack: err.stack }
|
||||
: {};
|
||||
|
||||
// Отправляем ответ клиенту
|
||||
res.status(statusCode).json({
|
||||
error: {
|
||||
code: errorCode,
|
||||
message: errorMessage,
|
||||
...devError
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = errorMiddleware;
|
||||
@@ -1,12 +1,14 @@
|
||||
const logger = (req, res, next) => {
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
const requestLogger = (req, res, next) => {
|
||||
const start = Date.now();
|
||||
|
||||
res.on('finish', () => {
|
||||
const duration = Date.now() - start;
|
||||
console.log(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
|
||||
logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = logger;
|
||||
module.exports = requestLogger;
|
||||
@@ -4,18 +4,18 @@ const { pool } = require('../db');
|
||||
|
||||
const sessionMiddleware = session({
|
||||
store: new pgSession({
|
||||
pool: pool,
|
||||
pool,
|
||||
tableName: 'session',
|
||||
createTableIfMissing: true,
|
||||
}),
|
||||
secret: process.env.SESSION_SECRET || 'your-secret-key',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production', // В production должно быть true
|
||||
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 дней
|
||||
httpOnly: true,
|
||||
maxAge: 24 * 60 * 60 * 1000, // 24 часа
|
||||
sameSite: 'none', // Для работы между разными доменами
|
||||
secure: process.env.NODE_ENV === 'production', // В production должно быть true
|
||||
sameSite: 'lax', // Попробуйте изменить на 'none' если используете разные домены
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user