Создание Базы Данных и Backend для Веб-Сайта Товаров и Услуг
Комплексное руководство по разработке безопасной и функциональной платформы
Ключевые Выводы
- Структура базы данных: Организуйте основные категории и подкатегории для товаров и услуг, обеспечивая гибкость и масштабируемость.
- Backend на Node.js: Используйте современные фреймворки и библиотеки для эффективного взаимодействия с PostgreSQL и управления API.
- Меры безопасности: Внедрите многоуровневую защиту, включая предотвращение SQL-инъекций, валидацию данных и безопасное хранение паролей.
1. Проектирование Структуры Базы Данных
1.1 Основные Таблицы
Для обеспечения эффективности и гибкости базы данных необходимо определить основные таблицы, которые будут хранить информацию о товарах, услугах, категориях, проектах, заказах и контактах.
Категории (categories)
id(Primary Key, SERIAL): Уникальный идентификатор категории.name(VARCHAR): Название категории.parent_id(INTEGER, Foreign Key): Ссылка на родительскую категорию для создания иерархии подкатегорий.created_at(TIMESTAMP): Дата и время создания категории.
Товары (products)
id(Primary Key, SERIAL): Уникальный идентификатор товара.category_id(INTEGER, Foreign Key): Ссылка на категорию товара.name(VARCHAR): Название товара.description(TEXT): Полное описание товара.short_description(VARCHAR): Краткое описание товара.price(DECIMAL): Цена товара.image_url(VARCHAR): Ссылка на изображение товара.created_at(TIMESTAMP): Дата и время добавления товара.
Услуги (services)
id(Primary Key, SERIAL): Уникальный идентификатор услуги.category_id(INTEGER, Foreign Key): Ссылка на категорию услуги.name(VARCHAR): Название услуги.description(TEXT): Полное описание услуги.short_description(VARCHAR): Краткое описание услуги.image_url(VARCHAR): Ссылка на изображение услуги.created_at(TIMESTAMP): Дата и время добавления услуги.
Примеры Проектов (project_examples)
id(Primary Key, SERIAL): Уникальный идентификатор проекта.service_id(INTEGER, Foreign Key): Ссылка на соответствующую услугу.name(VARCHAR): Название проекта.description(TEXT): Полное описание проекта.short_description(VARCHAR): Краткое описание проекта.image_url(VARCHAR): Ссылка на изображение проекта.created_at(TIMESTAMP): Дата и время добавления проекта.
Заказы (orders)
id(Primary Key, SERIAL): Уникальный идентификатор заказа.user_name(VARCHAR): Имя пользователя, сделавшего заказ.user_email(VARCHAR): Email пользователя.user_phone(VARCHAR): Телефон пользователя.order_details(TEXT): Детали заказа.total_price(DECIMAL): Общая сумма заказа.created_at(TIMESTAMP): Дата и время создания заказа.
Контакты (contacts)
id(Primary Key, SERIAL): Уникальный идентификатор сообщения.name(VARCHAR): Имя отправителя.email(VARCHAR): Email отправителя.message(TEXT): Текст сообщения.created_at(TIMESTAMP): Дата и время отправки сообщения.
1.2 Дополнительные Таблицы
Для более детального управления изображениями и деталями заказов рекомендуется добавить дополнительные таблицы.
Изображения Товаров (product_images)
id(Primary Key, SERIAL): Уникальный идентификатор изображения.product_id(INTEGER, Foreign Key): Ссылка на соответствующий товар.image_path(VARCHAR): Путь к изображению.is_main(BOOLEAN): Флаг основного изображения.
Изображения Проектов (project_images)
id(Primary Key, SERIAL): Уникальный идентификатор изображения.project_id(INTEGER, Foreign Key): Ссылка на соответствующий проект.image_path(VARCHAR): Путь к изображению.is_main(BOOLEAN): Флаг основного изображения.
2. Реализация Backend на Node.js
2.1 Основные Модули и Библиотеки
-
express: Фреймворк для создания сервера и управления маршрутизацией. -
pg: Библиотека для взаимодействия с PostgreSQL. -
dotenv: Управление переменными окружения. -
express-validator: Валидация входных данных. -
bcrypt: Хеширование паролей. -
jsonwebtoken: Управление JWT-токенами для аутентификации. -
helmet: Защита приложений через HTTP-заголовки. -
express-rate-limit: Ограничение количества запросов для предотвращения атак. -
multer: Обработка загрузки файлов.
2.2 Подключение к PostgreSQL
const { Pool } = require('pg');
require('dotenv').config();
const pool = new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: process.env.DB_PORT,
});
module.exports = pool;
2.3 Создание API Эндпоинтов
Получение Списка Товаров
const express = require('express');
const pool = require('./db');
const app = express();
app.use(express.json());
app.get('/products', async (req, res) => {
try {
const { rows } = await pool.query('SELECT * FROM products');
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).send('Server error');
}
});
Создание Нового Заказа
const { body, validationResult } = require('express-validator');
app.post('/orders', [
body('user_name').notEmpty(),
body('user_email').isEmail(),
body('user_phone').isMobilePhone(),
body('order_details').notEmpty(),
], async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { user_name, user_email, user_phone, order_details, total_price } = req.body;
try {
const newOrder = await pool.query(
'INSERT INTO orders (user_name, user_email, user_phone, order_details, total_price) VALUES ($1, $2, $3, $4, $5) RETURNING *',
[user_name, user_email, user_phone, order_details, total_price]
);
res.json(newOrder.rows[0]);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
Авторизация Администратора
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
app.post('/admin/login', async (req, res) => {
const { email, password } = req.body;
try {
const user = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
if (user.rows.length === 0) {
return res.status(400).json({ msg: 'Неверные учетные данные' });
}
const validPassword = await bcrypt.compare(password, user.rows[0].password);
if (!validPassword) {
return res.status(400).json({ msg: 'Неверные учетные данные' });
}
const token = jwt.sign({ id: user.rows[0].id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token });
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
2.4 Запуск Серверa
app.listen(3000, () => {
console.log('Сервер запущен на порту 3000');
});
3. Меры Безопасности
3.1 Защита от SQL-инъекций
Используйте параметризованные запросы через библиотеку pg, чтобы предотвратить выполнение вредоносных SQL-кодов.
// Пример параметризованного запроса
const { rows } = await pool.query('SELECT * FROM products WHERE id = $1', [productId]);
3.2 Валидация и Санитизация Данных
Применяйте библиотеки для валидации входных данных, такие как express-validator и joi, а также санитизируйте данные с помощью xss для предотвращения XSS-атак.
3.3 Хранение Паролей
Хешируйте пароли пользователей с помощью библиотеки bcrypt, чтобы обеспечить безопасность учетных записей.
// Хеширование пароля
const bcrypt = require('bcrypt');
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(password, saltRounds);
3.4 Аутентификация и Авторизация
Используйте JWT-токены для обеспечения безопасного доступа к административным функциям и защищенным маршрутам.
// Middleware для проверки JWT
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
3.5 Защита Веб-Сервера
Используйте helmet для установки безопасных HTTP-заголовков, а также запускайте сервер через HTTPS для защиты передаваемых данных.
const helmet = require('helmet');
app.use(helmet());
3.6 Ограничение Запросов
Применяйте express-rate-limit для предотвращения DDoS-атак и ограничения количества запросов с одного IP-адреса.
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 100, // лимит на 100 запросов
});
app.use(limiter);
3.7 Защита от CSRF-атак
Внедрите механизм защиты от CSRF-атак, используя соответствующие middleware или токены.
3.8 Хранение Конфиденциальных Данных
Используйте переменные окружения для хранения чувствительных данных, таких как пароли, секретные ключи и URL базы данных.
// Пример использования dotenv
require('dotenv').config();
const dbPassword = process.env.DB_PASSWORD;
4. Дополнительные Рекомендации
4.1 Управление Изменениями в Базе Данных
Используйте миграции с помощью инструментов, таких как knex.js или sequelize, для управления изменениями структуры базы данных.
4.2 Логирование и Мониторинг
Реализуйте систему логирования с помощью библиотек, таких как winston, для отслеживания ошибок и важной информации о работе приложения.
4.3 Резервное Копирование
Настройте регулярное резервное копирование базы данных для предотвращения потери данных.
4.4 Загрузка и Управление Изображениями
Используйте multer для обработки загрузки изображений, ограничивая размер файлов и типы файлов для повышения безопасности.
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 5000000 }, // 5MB
fileFilter: (req, file, cb) => {
const filetypes = /jpeg|jpg|png/;
const mimetype = filetypes.test(file.mimetype);
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb(new Error('Ошибка: Только изображения!'));
}
});
5. Заключение
Создание надежной и безопасной базы данных для веб-сайта, предоставляющего товары и услуги, требует тщательного планирования структуры данных, эффективной реализации backend-логики на Node.js и внедрения всесторонних мер безопасности. Следуя представленным рекомендациям, вы сможете создать масштабируемую, защищенную и функциональную платформу, отвечающую современным стандартам веб-разработки.
Ссылки на Рекомендуемые Ресурсы
Last updated January 20, 2025