Skip to content

Latest commit

 

History

History
1220 lines (1021 loc) · 96.4 KB

File metadata and controls

1220 lines (1021 loc) · 96.4 KB

Промежуточные обработчики

Промежуточные обработчики - необходимы в большинстве случаев как обработчики авторизации, валидации, аутентификации и других различных проверок. Промежуточные обработчики могут быть как внешними библиотеками, которые подключают глобально, так самописные промежуточные обработчики подключаемые локально в маршрутизаторы. Ниже будет подробно разобраны промежуточные обработчики, которые используются в приложении

⬅️ Подробную информацию обо всех маршрутах смотреть в разделе Маршрутизация.
⬅️ Подробную информацию обо всех контроллерах смотреть в разделе Контроллеры.
↩️ К оглавлению документации.

Оглавление раздела

Описание промежуточных обработчиков

Промежуточные обработчики могут быть как внешними библиотеками так и утилиты написаные самим разработчиком. Одновременно с этим, сами промежуточные обработчики могут быть подключение к приложению глобально, так и локально, в зависимости от бизнес-логики приложение.


Пример глобального подключения промежуточного обработчика

const flash = require('connect-flash')
app.use(flash())

Где:

  • connect-flash - библиотека из npm, которое отвечает за отображение валидированных ошибок.
  • app.use(flash()) - подключение библиотеки connect-flash к приложению.
  • app.use() - метод use объекта app, создающий подключение midlleware (промежуточных обработчиков) к приложения. Объект app является результатом работы функции express. Код подключения express ниже:
const express = require('express')
const app = express()

Пример локального промежуточного обработчика

const bcrypt = require('bcryptjs')

router.post('/login', async (req, res) => {
  const {email, password} = req.body
  const candidate = await User.findOne({ email })

  if (candidate) {
    const areSame = await bcrypt.compare(password, candidate.password)
  }
})

Где:

  • bcryptjs - библиотека из npm, которая шифрует строки.
  • router.post('/login', async (req, res) => {}) - маршрутизатор с методом запроса post, который. Подробнее о данном маршрутизаторе смотрите Метод запроса post по маршруту '/auth/login'
  • bcrypt.compare(password, candidate.password) - метод compare библиотеки bcryptjs, который сравнивает два значение. В данном примере - существующий пароль, который привязан к email пользователя с базы данных и вводимый кандидатом пароль.

Пример самописного промежуточного обработчика

module.exports = function(req, res, next) {
  if (!req.session.isAuthenticated) {
    return res.redirect('/auth/login')
  }

  next()
}

Где:

  • function(req, res, next) {}) - промежуточные обработчики отличаются наличием третъего аргумента next, который должен обязательно быть вызван вконце логики промежуточного обработчика.
  • if (!req.session.isAuthenticated) {} - проверка на авторизацию пользователя.
  • return res.redirect('/auth/login') - метод redirect объекта ответа response, который перенаправляет пользователя на страницу по маршуту '/auth/login'.
  • next() - обязательный параметр, определяет завершение логики кода данного промежуточного обработчика.

Таблица всех промежуточных обработчиков, которые реализованы в приложении:

Название Подключение Происхождение Короткое описание
bcryptjs Локально Библиотека bcryptjs Хеширует пароли
crypto Локально Библиотека crypto Генерирует криптографические байты
helmet Глобально Библиотека helmet Дополняет защиту приложения путём добавление заголовков HTTP
session Глобально Библиотека express-session Создаёт хранилище сессий
connect-flash Глобально Библиотека flash Выводит сообщения в случае ошибок валидации
csurf Глобально Библиотека csurf CSRF защита приложения
compression Глобально Библиотека compression Сжимает приложение в gzip для повышение быстродействия приложения
nodemailer Локально Библиотека nodemailer Формирование писем, которые будут отправляться по почте
fileMiddleware Глобально Файл file.js Обработка загружаемых картинок, которые использутся для аватара
auth Локально Файл auth.js Проверка на авторизацию пользователя
errorHandler Глобально Файл error.js Вывод страницы 404
registerValidators Локально Файл validators.js Выводит ошибки валидации при регистрации нового пользователя
courseValidators Локально Файл validators.js Выводит ошибки валидации при создании / редактировании одного курса
UserMiddleware Глобально Файл user.js Организация допуска авторизированым пользователям
varMiddleware Глобально Файл variables.js Создание токена CSRF для авторизированого пользователя

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.

Реализация библиотечных промежуточных обработчиков


bcryptjs

bcryptjs позволяет хешировать пароли. Поскольку манипуляции с пароля в приложении производятся в контроллерах авторизации, то и следовательно модуль подключается лишь здесь. Код подключения bcryptjs в файл auth.js:

const bcrypt = require('bcryptjs')

Использование bcryptjs в контроллере авторизации с методом запроса post по машруту /auth/login

Библиотека в данном контролере используется для сравнения существующего пароля привязанного к существуему email пользователя с базы данных и вводимый кандидатом пароль на получение авторизации. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/login', async (req, res) => {
...
  const {email, password} = req.body
  const candidate = await User.findOne({ email })

  if (candidate) {
    const areSame = await bcrypt.compare(password, candidate.password)
  }
  ...
...
})

Где:

  • router.post('/login', async (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/login' и callback функцию.
  • {email, password} - конкретные ключи деструктуризированные с тела объекта запроса request.body.
  • User.findOne({ email }) - метод findOne модели User, который ищет пользователя в базе данных MongoDB по его email.
  • bcrypt.compare(password, candidate.password) - метод compare библиотеки bcryptjs, который сравнивает существующий пароль, который привязан к email пользователя с базы данных и вводимый кандидатом пароль.

⬅️ Подробнее о контролере смотрите Метод запроса post по маршруту '/auth/login'.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование bcryptjs в контроллере авторизации с методом запроса post по машруту /auth/register

Библиотека в данном контролере используется для хеширования пароля пользователя, который регистрируется. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/register', registerValidators, async (req, res) => {
  ...
  const {email, password, name} = req.body
  ...
  const hashPassword = await bcrypt.hash(password, 10)
...
})

Где:

  • router.post('/register', registerValidators, async (req, res) => {}) - метод запроса post объекта router, который принимает 3 аргумента: путь '/register', промежуточный обработчик registerValidators и callback функцию.
  • registerValidators - промежуточный обработчик валидирующий ошибки при регистрации. Подробнее о данном промежуточном обработчике смотрите registerValidators.
  • {email, password, name} - конкретные ключи деструктуризированные с тела объекта запроса request.body.
  • bcrypt.hash(req.body.password, 10) - метод hash библиотеки bcrypt, который принимает 2 аргумента: вводимый пользователем пароль req.body.password и количество хешируемых символов - 10.

⬅️ Подробнее о контролере смотрите Метод запроса post по маршруту '/auth/register'.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование bcryptjs в контроллере авторизации с методом запроса post по машруту /auth/password

Библиотека в данном контролере используется для хеширования вводимого пароля. Часть кода контроллера, работающий с промежуточным обработчиком:

router.post('/password', async (req, res) => {
  ...
  if (user) {
    user.password = await bcrypt.hash(req.body.password, 10)
    ...
})

Где:

  • router.post('/password', async (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/password' и callback функцию.
  • bcrypt.hash(req.body.password, 10) - метод hash библиотеки bcrypt, который принимает 2 аргумента: вводимый пользователем пароль req.body.password и количество хешируемых символов - 10.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/password'.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


crypto

crypto необходим для генерации криптографически хорошо построенных искусственных случайных данных, которые в последствии будут отправлятся пользователю как уникальная ссылка для смены пароля пользователем. Код подключение и использование crypto в файле auth.js:

const crypto = require('crypto')
...
router.post('/reset', (req, res) => {
    crypto.randomBytes(32, async (err, buffer) => {})
...
})

Где:

  • crypto - библиотека crypto.
  • router.post('/reset', (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/reset' и callback функцию.
  • crypto.randomBytes(32, async (err, buffer) => {}) - метод randomBytes библиотеки crypto, который генерирует криптографические данные.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/reset'.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.
⬆️ К оглавлению раздела.


helmet

helmet помогает защитить приложение от некоторых широко известных веб-уязвимостей путем соответствующей настройки заголовоков HTTP. Код отвечающий за настройку и подключение helmet в главный файл index.js:

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      ...helmet.contentSecurityPolicy.getDefaultDirectives(),
      "img-src": ["'self'", "https:"],
      "script-src-elem": ["'self'", "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js", "'unsafe-inline'" ] 
    },
  },
}))

Где:

  • helmet - оболочка для различных промежуточных обработчиков, которые установлены по умолчанию.
  • contentSecurityPolicy: {}) - промежуточный обработчик, который устанавливает специфические настройки заголовка Content-Security-Policy.
  • directives - объект, где ключи - это название директив.
  • ...helmet.contentSecurityPolicy.getDefaultDirectives() - объект директив по умолчанию.
  • "img-src": ["'self'", "https:"] - ряд параметров для защиты подключаемых картинок.
  • "script-src-elem": ["'self'", "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js", "'unsafe-inline'" ] - ряд параметром для защиты подключаемых скриптов.

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


express-session

express-session создаёт объект сессии, данные которой хранятся на стороне сервера. Код, отвечающий за подключение и настройку express-session в главном файле index.js:

const session = require('express-session')
... 
app.use(session({
  secret: keys.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  store
}))

Где:

  • session - оболочка принимающая ряд параметров настройки session.
  • secret: keys.SESSION_SECRET - уникальный ключ сессий.
  • resave: false - принудительное сохранение сеанса в хранилище сессий, даже если сеанс не изменялся во время запроса, true по умолчание. Значение false выставляется для избежания ошибок в случае параллельных запросов пользователем.
  • saveUninitialized: false - сохранение неинициализированных сеансов в хранилище сессий, true по умолчанию. Значение false выставляется во избежания ошибок в случае параллельных запросов пользователем и уменьшения использования хранилище сервера.
  • store - ключ принимающий одноименное значение объекта store. Код объекта store указан ниже:
const MongoStore = require('connect-mongodb-session')(session)
...
const store = new MongoStore({
  collection: 'sessions',
  uri: keys.MONGODB_URL
})

Где:

  • MongoStore({}) - объект устанавливающий соединение express приложения и хранилище сессий в MongoDB.
  • collection: 'sessions' - название коллекции сессий в базе данных MongoDB.
  • uri: keys.MONGODB_URL - URL путь соединения с базой данных MongoDB.

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


connect-flash

connect-flash необходим как специальная область сеанса, которая используется для хранения сообщений. Сообщения используется в связке с перенаправлениями во время действий авторизации. Сам connect-flash подключается в главном файле index.js после чего используется локально в контроллерах авторизации. Подробнее о контроллерах авторизации смотрите Контроллеры страницы "Вход / Выход". Код подключения connect-flash в главном файле index.js:

const flash = require('connect-flash')
app.use(flash())

Использование connect-flash в контроллере авторизации с методом запроса get по машруту /auth/login

Библиотека в данном контролере используется для вывода ошибок валидации при вводе почты и пароля пользователя. Часть кода контроллера работающий с промежуточным обработчиком:

router.get('/login', async (req, res) => {
  res.render('auth/login', {
    ...
    loginError: req.flash('loginError'),
    registerError: req.flash('registerError')
  })
})

Где:

  • router.get('/login', async (req, res) => {}) - метод запроса get объекта router, который принимает 2 аргумента: путь '/login' и callback функцию.
  • res.render('auth/login', {}) - метод render объекта res отправляет данные в объекте ответа для последующей визуализации представления шаблонизатором handlebars.
  • loginError: req.flash('loginError') - ключ loginError принимающий значение сообщения ошибки валидации приходящее с телом запроса req. В зависимости от данных введённых пользователем, может вывести текст "Неверный пароль" или "Такого пользователя не существует". Часть кода представления работающий с валидатором:
<div id="login" class="col s6 offset-s3">
...
  {{#if loginError}}
    <p class="alert">{{loginError}}</p>
  {{/if}}
...
</div>
  • registerError: req.flash('registerError') - ключ registerError принимающий значение сообщения ошибки валидации приходящее с телом запроса req. Часть кода представления работающий с валидатором:
<div id="login" class="col s6 offset-s3">
...
  {{#if registerError}}
    <p class="alert">{{registerError}}</p>
  {{/if}}
...
</div>

⬅️ Подробнее о данном контролере смотрите Метод запроса get по маршруту '/auth/login'.
⬅️ Подробнее о данном представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса get по машруту /auth/reset

Библиотека в данном контролере используется для вывода ошибок валидации при вводе данных для сброса пароля. Часть кода контроллера работающий с промежуточным обработчиком:

router.get('/reset', (req, res) => {
  res.render('auth/reset', {
    ...
    error: req.flash('error')
  })
})

Где:

  • router.get('/reset', (req, res) => {}) - метод запроса get объекта router, который принимает 2 аргумента: путь '/reset' и callback функцию.
  • res.render('auth/reset', {}) - метод render объекта res отправляет данные в объекте ответа для последующей визуализации представления шаблонизатором handlebars.
  • error: req.flash('error') - ключ error принимающий значение сообщения ошибки валидации приходящее с телом запроса req.

⬅️ Подробнее о данном контролере смотрите Метод запроса get по маршруту '/auth/reset'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса get по машруту /auth/password/:token

Библиотека в данном контролере используется для вывода ошибок валидации при вводе данных для создания нового пароля. Часть кода контроллера работающий с промежуточным обработчиком:

router.get('/password/:token', async (req, res) => {
    ...
    res.render('auth/password', {
    error: req.flash('error')
  })
...
})

Где:

  • router.get('/password/:token', async (req, res) => {}) - метод запроса get объекта router, который принимает 2 аргумента: путь '/password/:token' и callback функцию.
  • res.render('auth/password', {}) - метод render объекта res отправляет данные в объекте ответа для последующей визуализации представления шаблонизатором handlebars.
  • error: req.flash('error') - ключ error принимающий значение сообщения ошибки валидации приходящее с телом запроса req.

⬅️ Подробнее о данном контролере смотрите Метод запроса get по маршруту '/auth/password/:token'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса post по машруту /auth/login

Библиотека в данном контролере используется для вывода ошибок валидации при вводе ошибочных или несуществующих данных пользователем в окне авторизации в свой аккаунт. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/login', async (req, res) => {
    ...
        req.session.save(err => {
          if (err) {
            throw err
          }
          res.redirect('/')
        })
      } else {
        req.flash('loginError', 'Неверный пароль')
        res.redirect('/auth/login#login')
      }
    } else {
      req.flash('loginError', 'Такого пользователя не существует')
      res.redirect('/auth/login#login')
    }
...
})

Где:

  • router.post('/login', async (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/login' и callback функцию.
  • req.flash('loginError', 'Неверный пароль') - метод flash принимающий 2 аргумента: название ошибки 'loginError' и текст ошибки 'Неверный пароль'.
  • res.redirect('/auth/login#login') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/login#login.
  • req.flash('loginError', 'Такого пользователя не существует') - метод flash принимающий 2 аргумента: название ошибки 'loginError' и текст ошибки 'Такого пользователя не существует'.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/login'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса post по машруту /auth/register

Библиотека в данном контролере используется для вывода ошибок валидации при вводе регистрируемых данных пользователем. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/register', registerValidators, async (req, res) => {
    ...
    if (!errors.isEmpty()) {
      req.flash('registerError', errors.array()[0].msg)
      return res.status(422).redirect('/auth/login#register')
...
})

Где:

  • router.post('/register', registerValidators, async (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/register' и callback функцию.
  • (!errors.isEmpty()) {} - если поле валидации наличивает символы - выполняется тело условия.
  • req.flash('registerError', errors.array()[0].msg) - поскольку валидатор ошибки у нас проверяется в представлении, то текст ошибки нам не обязательно делать смысловым на стороне сервера.
    На стороне сервера в случае ошибки валидации будет выводится первое значение встроенных текстов в объекте errors, которое приведённое к массиву, чтобы забрать текст ошибки по его индексу. Сам текст ошибки выглядит так: "Invalid value".
  • return res.status(422).redirect('/auth/login#register') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/login#register.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/register'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса post по машруту /auth/reset

Библиотека в данном контролере используется для вывода ошибок валидации при вводе почты, привязанный пароль к которой пользователь забыл и хочет сбросить. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/reset', (req, res) => {
    ...
    crypto.randomBytes(32, async (err, buffer) => {
      if (err) {
        req.flash('error', 'Что-то пошло не так, повторите попытку позже')
        return res.redirect('/auth/reset')
      }

      if (candidate) {
      ...
        await transporter.sendMail(resetEmail(candidate.email, token))
        res.redirect('/auth/login')
      } else {
        req.flash('error', 'Такого email нет')
        res.redirect('/auth/reset')
      }
...
})

Где:

  • crypto.randomBytes(32, async (err, buffer) => {}) - метод randomBytes библиотеке crypto, который генерирует хорошо построенные криптографические искусственные данные.
  • req.flash('error', 'Что-то пошло не так, повторите попытку позже') - метод flash принимающий 2 аргумента: название ошибки 'error' и текст ошибки 'Что-то пошло не так, повторите попытку позже'.
  • return res.redirect('/auth/reset') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/reset.
  • transporter.sendMail(resetEmail(candidate.email, token)) - метод sendMail объекта transporter отправляющий форму письма resetEmail по адресу email и токен смены пароля token.
  • res.redirect('/auth/login') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/login.
  • req.flash('error', 'Такого email нет') - метод flash принимающий 2 аргумента: название ошибки 'error' и текст ошибки 'Такого email нет'.
  • res.redirect('/auth/reset') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/reset.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/reset'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.


Использование connect-flash в контроллере авторизации с методом запроса post по машруту /auth/password

Библиотека в данном контролере используется для вывода ошибок валидации вводе нового пароля пользователем. Часть кода контроллера работающий с промежуточным обработчиком:

router.post('/password', async (req, res) => {

    if (user) {
      user.password = await bcrypt.hash(req.body.password, 10)
      ...
      res.redirect('/auth/login')
    } else {
      req.flash('loginError', 'Время жизни токена истекло')
      res.redirect('/auth/login')
    }
...
})

Где:

  • router.post('/password', async (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента: путь '/password' и callback функцию.
  • bcrypt.hash(req.body.password, 10) - метод hash библиотеки bcrypt который принимает два аргумента: вводимый пользователем пароль req.body.password и количество хешируемых символов - 10.
  • res.redirect('/auth/login') - метод redirect объекта res перенаправляет пользователя на страницу по маршруту /auth/login.
  • req.flash('loginError', 'Время жизни токена истекло') - метод flash принимающий 2 аргумента: название ошибки 'loginError' и текст ошибки 'Время жизни токена истекло'.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/password'.
⬅️ Подробнее о представлении смотрите Вход / Регистрация.
⬅️ Подробнее о реализации машрутизатора смотрите Реализация маршрутов.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


csurf

csrf используется для защиты от подделки межасайтовых запросов (CSRF). Код подключения connect-flash в главный файл index.js:

const csrf = require('csurf')
app.use(csrf())

Использование csrf защиты выходит путём подключения скритого обработчика csrf в шаблони handlebars. Часть кода шаблонизатора cтраницы "Добавить курс" add.hbs который работает с промежуточным обработчиком csurf:

<form action="/add" method="POST">
  ...
  <input type="hidden" name="_csrf" value="{{csrf}}">
  ...
</form>  

Где:

  • form action="/add" method="POST" - форма контроллера с методом запроса post по машруту /add.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - промежуточный обработчик csurf не отображающийся в представлении, но при этом обеспечивает создание токена. Этот токен проверяется по сеансу пользователя.

Использование csurf в представлении страницы "Корзина"

Часть кода шаблонизатора cтраницы "Корзины" card.hbs который работает с промежуточным обработчиком csurf:

{{#each courses}}
...
<button 
  class="btn btm-small js-remove" 
  data-id="{{id}}"
  data-csrf="{{@root.csrf}}"   
  >Удалить</button>
...
{{/each}}

<form action="/orders" method="POST"> 
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form> 

Где:

  • data-csrf="{{@root.csrf}}" - поле, которое визуализирует кнопку "Удалить" только для авторизированного пользователя владеющего токеном защиты CSRF.
  • form action="/orders" method="POST" - форма контроллера с методом запроса post по машруту /orders.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

Использование csurf в представлении страницы редактирования одного курса

Часть кода шаблонизатора cтраницы редактирования одного курса course-edit.hbs который работает с промежуточным обработчиком csurf:

<form action="/courses/edit" method="POST" class="course-form">
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>
...
<form action="/courses/remove" method="POST">
 <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/courses/edit" method="POST" - форма контроллера с методом запроса post по машруту /courses/edit.
  • form action="/courses/remove" method="POST" - форма контроллера с методом запроса post по машруту /courses/remove.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

Использование csurf в представлении страницы "Курсы"

Часть кода шаблонизатора cтраницы "Курсы" courses.hbs который работает с промежуточным обработчиком csurf:

{{#if @root.isAuth}}
  <form action="/card/add" method="POST">
    <input type="hidden" name="_csrf" value="{{@root.csrf}}"> 
  </form>
{{/if}}

Где:

  • @root.isAuth - права авторизированного пользовтаеля. Подробнее о правах смотрите промежуточных обработчик varMiddleware.
  • form action="/card/add" method="POST" - форма контроллера с методом запроса post по машруту /card/add.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

Использование csurf в представлении страницы "Профиль"

Часть кода шаблонизатора cтраницы "Профиль" profile.hbs который работает с промежуточным обработчиком csurf:

<form action="/profile" method="POST" enctype="multipart/form-data">
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/profile" method="POST" enctype="multipart/form-data" - форма контроллера с методом запроса post по машруту /profile.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

Использование csurf в представлении страницы "Авторизация"

Раздел логин

Часть кода шаблонизатора cтраницы авторизации раздела "Логин" auth/login.hbs который работает с промежуточным обработчиком csurf:

<form action="/auth/login" method="POST">
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/auth/login" method="POST" - форма контроллера с методом запроса post по машруту /auth/login.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/login'.

Раздел Регистрация

Часть кода шаблонизатора cтраницы авторизации раздела "Регистрация" auth/login.hbs который работает с промежуточным обработчиком csurf:

<form action="/auth/register" method="POST" novalidate>
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/auth/register" method="POST" novalidate - форма контроллера с методом запроса post по машруту /auth/register.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/register'.

Раздел сброса пароля

Часть кода шаблонизатора cтраницы авторизации раздела "Востановление пароля" auth/password.hbs который работает с промежуточным обработчиком csurf:

 <form action="/auth/password" method="POST">
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/auth/password" method="POST" - форма контроллера с методом запроса post по машруту /auth/password.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/password'.

Раздел смены пароля

Часть кода шаблонизатора cтраницы авторизации раздела "Сбросить пароль" auth/reset.hbs который работает с промежуточным обработчиком csurf:

 <form action="/auth/reset" method="POST">
  <input type="hidden" name="_csrf" value="{{csrf}}">
</form>

Где:

  • form action="/auth/reset" method="POST" - форма контроллера с методом запроса post по машруту /auth/reset.
  • <input type="hidden" name="_csrf" value="{{csrf}}"> - токен промежуточного обработчика csurf, который проверяется по сеансу пользователя.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/reset'.
⬅️ Подробнее о представлении, которое использует данные переданные вместе с методом render объекта ответа response смотрите Вход / Регистрация.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


compression

compression необходим как модуль для сжатия gzip, чтобы уменьшенить размер тела ответа и соответственно, увеличить быстродействие веб-приложения. Код подключения промежуточного обработчика в главний файл index.js:

const compression = require('compression')
app.use(compression())

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


fileMiddleware

fileMiddleware использует библиотеку multer для обработки загружаемых файлов. Код подключения и реализации логики обработки загружаемых картинок:

const multer = require('multer')

const storage = multer.diskStorage({
  destination(req, file, cb) {
    cb(null, 'images')
  },
  filename(req, file, cb) {
    cb(null, file.originalname)
  }
})

const allowedTypes = ['image/png', 'image/jpg', 'image/jpeg']

const fileFilter = (req, file, cb) => {
  if (allowedTypes.includes(file.mimetype)) {
    cb(null, true)
  } else {
    cb(null, false)
  }
}

module.exports = multer({
  storage, fileFilter
})

Где:

  • multer.diskStorage({}) - метод diskStorage библиотеки multer, которая сохраняет файлы. Принимает 2 аргумента, каждый из которых является функцией:
    • destination(req, file, cb) {} - метод определяющий место сохранения загружаемых файлов, в нашем случае - папка "images".
    • filename(req, file, cb) {} - метод определяющий имя для загружаемых файлов, в нашем случае сохраняется оригинальное имя файла.
  • allowedTypes = ['image/png', 'image/jpg', 'image/jpeg'] - массив расширений файлов, которые могут загружатся.
  • fileFilter = (req, file, cb) => {} - метод определяющий фильтр файлов, которые могут принимается.
  • if (allowedTypes.includes(file.mimetype)) {} - условие, при котором, если файл имеет расширение указаное в массиве allowedTypes, то выполняется тело условия.
  • cb(null, true) - если условие проходит сохраняем файл (значение true).
  • cb(null, false) - если условие не проходит, тогда файл не сохраняется (значение false).
  • multer({storage, fileFilter}) - объект multer принимающий параметры хранилища storage и фильтр fileFilter.

Подключение промежуточного обработчика в главный файл index.js:

const fileMiddleware = require('./midlleware/file')
app.use(fileMiddleware.single('avatar'))

Где:

  • fileMiddleware.single('avatar') - привязка промежуточного обработчика к полю в шаблонизаторе с названием "avatar".

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


nodemailer-sendgrid-transport

nodemailer-sendgrid-transport необходим для отправки пользователю писем на почту, которую пользователь вводил при регистрации в следующих ситуациях:

Тип письма Задача письма
Подтверждение регистрации Уведомить пользователя об подтверждении успешной регистрации
Восстановление пароля Прислать токен с ограниченным сроком жизни для смены пароля

Подключение всех зависимостей nodemailer-sendgrid-transport

nodemailer-sendgrid-transport подключается локально в контроллеры отвечающие за регистрацию и восстановление пароля пользователя. Код подключения сервиса nodemailer и промежуточного обработчика отправки писем nodemailer-sendgrid-transport в файл auth.js:

const nodemailer = require('nodemailer')
const sendgrid = require('nodemailer-sendgrid-transport')

Где:

  • nodemailer - сервис nodemailer.
  • sendgrid - плагин сервиса nodemailer позволяющий создать связь Node.js сервера с сервисом nodemailer.

Подключение файлов с формой письма с уведомлением и подтверждении успешной регистрации и письма с уведомлением о смене пароля в файл auth.js:

const regEmail = require('../emails/registration')
const resetEmail = require('../emails/reset')

Где:

  • regEmail - форма письма об успешной регистрации.
  • resetEmail - форма письма о сбросе пароля.

Для создание механизма отправки писем необходимо связать сервис nodemailer и промежуточный обработчик sendGrid путём создания транспорта с уникалньым ключём авторизации в сервисе nodemailer. Код подключения уникального ключа nodemailer к промежуточному обработчику sendGrid:

const transporter = nodemailer.createTransport(sendgrid({
  auth: {api_key: keys.SENDGRID_API_KEY}
}))

Где:

  • nodemailer.createTransport(sendgrid({})) - метод createTransport объекта nodemailer создающий связь между сервисом nodemailer и сервером Node.js.
  • auth: {api_key: keys.SENDGRID_API_KEY} - объект авторизации auth принимающий значение секретного ключа nodemailer, зарезервированным свойством api_key. Секретный ключ nodemailer является уникальным и генерируется при прохождении процедуры создания акаунта в сервисе nodemailer. Чтобы узнать как получить секретный ключ nodemailer смотрите Получение SENDGRID_API_KEY.

⬆️ К оглавлению раздела.

Письмо подтверждающее успешную регистрацию

В случае успешной регистрации контроллер регистрации с методом post по маршруту /auth/register отправляет данные нового пользователя в базу данных, а после отправляет письмо об успешной регистрации на почту, котору указатель пользователь. Часть кода контроллера работающего с промежуточным обработчиком nodemailer-sendgrid-transport:

router.post('/register', registerValidators, async (req, res) => {
    const {email, password, name} = req.body
    ...
    await user.save()
    await transporter.sendMail(regEmail(email))
    ...
})

Где:

  • router.post('/register', registerValidators, async (req, res) => {}) - метод запроса post объекта router, который принимает 3 аргумента:
    • '/edit' - обязательный параметр, который определяет маршрут запроса.
    • registerValidators - необязательный параметр. Промежуточный обработчик, проверяющий права пользователя на редактирование курса.
    • async (req, res) => {}) - обязательный параметр. Callback-функция.
  • {email, password, name} - одноимённые ключи деструктуризированные из тела объекта запроса req.body.
  • user.save() - метод save модели user сохраняющая данные в базы данных MongoDB.
  • transporter.sendMail(regEmail(email)) - метод sendMail объекта transporter отправляющий форму письма regEmail по адресу email.

Код формы письма успешной регистрации:

module.exports = function(email) {
  return {
    to: email,
    from: keys.EMAIL_FROM,
    subject: 'Аккаунт создан',
    html: `
      <h1>Добро пожаловать в наш магазин</h1>
      <p>Вы успешно создали аккаунт c email - ${email}</p>
      <hr />
      <a href="${keys.BASE_URL}">Магазин курсов</a>
    `
  }
}

Где:

  • function(email) {} - функция принимащая аргумент почты email.
  • return {} - функция возвращает объект.
  • to: email - ключ to принимающий значение адреса получателя письма.
  • from: keys.EMAIL_FROM - ключ from принимающий значение адреса отправителя письма.
  • subject: 'Аккаунт создан' - ключ subject определяющий тему письма.
  • html: ... - текст письма, определённый в структуре HTML форме.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/register'.
⬆️ К оглавлению раздела.

Письмо смены пароля

В случае успешной регистрации контроллер регистрации с методом post по маршруту /auth/reset отправляет токен для сброса пароля, а после отправляет письмо с токеном сброса пароля на почту пользователя. Часть кода контроллера работающего с промежуточным обработчиком nodemailer-sendgrid-transport:

router.post('/reset', (req, res) => {
    ...
    const token = buffer.toString('hex')
    const candidate = await User.findOne({email: req.body.email})
    ...
    await transporter.sendMail(resetEmail(candidate.email, token))
    ...
})

Где:

  • router.post('/reset', (req, res) => {}) - метод запроса post объекта router, который принимает 2 аргумента:
    • '/reset' - обязательный параметр, который определяет маршрут запроса.
    • async (req, res) => {}) - обязательный параметр. Callback-функция.
  • buffer.toString('hex') - метод toString привядящий к строке аргумент buffer выводящий 32значное число.
  • User.findOne({email: req.body.email}) - метод findOne моделит User, находит почту пользователя из базы данных email которая совпадает со значением почты приходящим в поле запроса req.body.email.
  • transporter.sendMail(resetEmail(candidate.email, token)) - метод sendMail объекта transporter отправляющий форму письма resetEmail по адресу email и токен смены пароля token.

Код формы письма сброса пароля:

module.exports = function(email, token) {
    return {
        to: email,
        from: keys.EMAIL_FROM,
        subject: 'Восстановление доступа',
        html: `
          <h1>Вы забыли пароль?</h1>
          <p>Если нет, то проигнорируйте данное письмо</p>
          <p>Иначе нажмите на ссылку ниже: </p>
          <p><a href="${keys.BASE_URL}/auth/password/${token}">Восстановить пароль</a></p>
          <hr />
          <a href="${keys.BASE_URL}">Магазин курсов</a>
        `
      }
}

Где:

  • function(email, token) {} - функция принимащая аргумент почты email.
  • return {} - функция возвращает объект.
  • to: email - ключ to принимающий значение адреса получателя письма.
  • from: keys.EMAIL_FROM - ключ from принимающий значение адреса отправителя письма.
  • subject: 'Восстановление доступа' - ключ subject определяющий тему письма.
  • html: ... - текст письма, определённый в структуре HTML форме.

⬅️ Подробнее о данном контролере смотрите Метод запроса post по маршруту '/auth/reset'.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


Реализация самописных промежуточных обработчиков

auth

auth необходим для проверки сессии пользователя. Код промежуточного обработчика:

module.exports = function(req, res, next) {
    if (!req.session.isAuthenticated) {
        return res.redirect('/auth/login')
    }

    next()
}

Где:

  • if (!req.session.isAuthenticated) {} - условие, которое выполняется если сессия пользователя не авторизована.
  • return res.redirect('/auth/login') - метод redirect объекта ответа res, который перенаправляет пользователя по машруту '/auth/login'.
  • next() обязательный параметр промежуточного обработчика, отвечающий за определение окончание кода промежуточного обработчика и позволяющий компилятору считывать дальнейший код приложения.

Подключение промежуточного обработчика происходит локально в соответствующие машрутизаторы. Перечень всех страниц с типами запроса и машрутизаторами показан в таблице "Все страницы с типами запросами и маршрутизаторами которые обрабатываются промежуточным обработчиком auth".

Все страницы с типами запросами и маршрутизаторами которые обрабатываются промежуточным обработчиком auth

Название страницы Метод запроса URL-путь запроса Краткое описание
Главная get "/" Получение страницы "Главная"
Курсы get "/courses" Получение страницы "Курсы" и получение всех курсов магазина
Курсы get "/courses/:id" Получение одного курса из магазина
Курсы get "/courses/:id/edit" Получение страницы "Редактирование одного курса"
Курсы post "/courses/edit" Отправка редактируемых данных старого курса
Курсы post "/courses/remove" Удаление существующего курса
Добавить курс get "/add" Получение страницы "Добавить курс"
Добавить курс post "/add" Отправка и сохранение одного курса и последующего перенаправления на страницу курсов
Профиль get "/profile" Получение страницы профиля пользователя
Профиль post "/profile" Отправка редактируемых данных профиля пользователя
Корзина get "/card" Получение страницы "Корзина" и всех товаров
Корзина post "/card/add" Добавление товара в "Корзину" c помощью клавиши "Купить" на странице "Курсы"
Корзина delete "/card/remove/:id" Удаление одного курса
Заказы get "/orders" Получение страницы "Заказы"
Заказы post "/orders" Отправка данных на страницу "Заказы" через клавишу "Сделать заказ" на странице "Корзина"

Интеграция промежуточного обработчика auth в машрутизаторы выглядит следующим образом:

router.post('/', auth,  async (req, res) => {})

Где:

  • router.post() - метод запроса post объекта router, который принимает 3 аргумента:
    • '/' - обязательный параметр, который определяет маршрут запроса.
    • auth - необязательный параметр. Промежуточный обработчик, проверяющий права пользователя на редактирование курса.
    • async (req, res) => {} - обязательный параметр, callback функция.

⬅️ Подробнее о контроллерах смотрите раздел Контроллеры.
⬅️ Подробнее о маршрутизаторах смотрите раздел Маршрутизация.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


errorHandler

errorHandler необходим для перенаправление на страницу 404, если пользователь делает get запрос на несуществующую страницу. Код промежуточного обработчика errorHandler:

module.exports = function(req, res, next) {
    res.status(404).render('404', {
        title: 'Страница не найдена'
    })
}

Где:

  • function(req, res, next) {} - функция промежуточного обработчика принимающая 3 аргумента: объект запроса req, объект ответа res и функцию next определяющую окончание кода промежуточного обработчика и позволяющая компилятору считывать следующий, за промежуточным обработчиком, код программы.
  • res.status(404) - метод status объекта ответа res, который отправляет тип кода сервера (404).
  • render('404', {} - метод render объекта ответа res, которая вторым аргументом отправляет объект с вложенными данными, а первым аргументом определяет шаблон последующей визулизации данных.
  • title: 'Страница не найдена' - вложенные данные отправленные в шаблон, где ключ title принимающий значение строки 'Страница не найдена'.

Подключение промежуточного обработчика errorHandler в главный файл index.js:

const errorHandler = require('./midlleware/error')
app.use(errorHanler)

Важно! обработчик должен быть подключён после маршрутизаторов (порядок подключения модулей машрутизаторов и промежуточного обработчика errorHandler в файл index.js неважен), чтобы сервер верно считывал код существующий страниц:

...
app.use('/', homeRoutes)
app.use('/add', addRoutes)
app.use('/courses', coursesRoutes)
app.use('/card', cardRoutes)
app.use('/orders', ordersRoutes)
app.use('/auth', authRoutes)
app.use('/profile', profileRoutes)

app.use(errorHanler)

Где:

  • app.use('/', homeRoutes) - метод use объекта app принимающий 2 параметра: корневой путь машрутизатора '/' и callback-функцию homeRoutes.
  • app.use(errorHanler) - метод use объекта app принимающий промежуточный обработчик errorHanler.

⬅️ Подробнее о маршрутизаторах смотрите раздел Маршрутизация.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


registerValidators

registerValidators валидирует данные, вводимые пользователем во время регистрации нового аккаунта, поскольку каждое поле имеет свои собственные условия валидации, то registerValidators это массив состоящий из объектов с различными свойствами:

registerValidators = []

Валидация регистрируемой почты

Код, отвечающий за валидацию регистрируемой почты:

    body('email')
    .isEmail()
    .withMessage('Введите корректный email')
    .custom(async (value, req) => {
        try {
            const user = await User.findOne({email: value})
            if (user) {
                return Promise.reject('Такой email уже занят')
            }
        } catch (e) {
            console.log(e)
        }
      .normalizeEmail()
    })

Где:

  • body('email') - поле с названием контейнера email.
  • .isEmail() - валидация на наличие символа "@".
  • .withMessage('Введите корректный email') - функция withMessage выводящая текст ошибки валидации 'Введите корректный email'.
  • .custom(async (value, req) => {}) - уникальная функция.
  • User.findOne({email: value}) - метод findOne модели User, который находит почту пользователя в базе данных по значению value.
  • Promise.reject('Такой email уже занят') - объект Promise возвращающий ошибку reject с текстом 'Такой email уже занят' в случае, если в базе существует пользователь с таким email.
  • normalizeEmail() - приводит строку со значением email к формату email.

Валидация регистрируемого пароля

Код, отвечающий за валидацию регистрируемого пароля:

...
    body('password', 'Пароль должен быть минимум 6 символов')
    .isLength({min: 6, max: 56})
    .isAlphanumeric()
    .trim()
...

Где:

  • body('password', 'Пароль должен быть минимум 6 символов') - поле с названием контейнера password, при заполнении меньше 6 символов выводит ошибку валидации с текстом 'Пароль должен быть минимум 6 символов'.
  • .isLength({min: 6, max: 56}) - функция isLength принимающая два параметра: минимальное количество символов - 6 и максимальное количество символов - 56.
  • .isAlphanumeric() - валидация, которая позволяет заполнять поле только английским алфавитом.
  • .trim() - функция убирающая пробелы.

Валидация подтверждения пароля

Код отвечающий за валидацию подтверждение пароля:

...
    body('confirm') 
    .custom((value, {req}) => {
        if (value !== req.body.password) {
            throw new Error('Пароли должны совпадать')
        }
        return true
    })
    .trim()
...

Где:

  • body('confirm') - поле с названием контейнера confirm.
  • .custom((value, {req}) => {}) - уникальная функция.
  • if (value !== req.body.password) {} - условие, при котором, если значение в поле confirm не равняется значению из тела запроса req.body.password, тогда выполняется тело условия.
  • throw new Error('Пароли должны совпадать') - при несовпадении паролей выводится ошибка валидации с текстом 'Пароли должны совпадать'.
  • .trim() - функция убирающая пробелы.

Валидация регистрируемого имени

Кода отвечающий за валидацию регистрируемого имени пользователя:

...
body('name')
    .isLength({min: 3})
    .withMessage('Имя не может быть короче трёх символов')
    .trim()
...

Где:

  • body('name') - поле с названием контейнера name.
  • .isLength({min: 3}) - функция isLength, которая при заполнении поля name меньше чем 3 символа выводит ошибку валидации с текстом 'Имя не может быть короче трёх символов'.
  • .withMessage('Имя не может быть короче трёх символов') - функция withMessage выводящая текст ошибки валидации 'Имя не может быть короче трёх символов'.
  • .trim() - функция убирающая пробелы.

Подключение промежуточного обработчика registerValidators

Подключение промежуточного обработчика происходит локально в маршрутизатор регистрации с методом запроса post:

router.post('/register', registerValidators, async (req, res) => {})

Где:

  • router.post() - метод запроса post объекта router, который принимает 3 аргумента:
    • '/register' - обязательный параметр, который определяет маршрут запроса.
    • registerValidators - необязательный параметр. Промежуточный обработчик, валидирующий вводимые данные при регистрации нового пользователям.
    • async (req, res) => {} - обязательный параметр, callback-функция.

⬅️ Подробнее о данном контролере смотрите раздел Метод запроса post по маршруту '/auth/register'.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


courseValidators

courseValidators валидирует данные вводимые при создании или редактировании одного курса, поскольку каждое поле имеет свои собственные условия валидации, то courseValidators это массив состоящий из объектов с различными свойствами:

courseValidators = [
    body('title').isLength({min: 3}).withMessage('Минимальная длина названия три символа').trim(),
    body('price').isNumeric().withMessage('Введите корректную цену'),
    body('img', 'Введите корректный Url картинки').isURL()
]

Где:

  • body('title') - поле с названием контейнера title.
    • .isLength({min: 3}) - функция isLength, которая при заполнении поля name меньше чем 3 символа выводит ошибку валидации с текстом 'Минимальная длина названия три символа'.
    • .withMessage('Минимальная длина названия три символа') - функция withMessage выводящая текст ошибки валидации 'Минимальная длина названия три символа'.
    • .trim() - функция убирающая пробелы.
  • body('price') - поле с названием контейнера price.
    • .isNumeric() - функция валидации позволяющая вводить только цифровые символы в поле price.
    • .withMessage('Введите корректную цену') - функция withMessage выводящая текст ошибки валидации 'Введите корректную цену'.
  • body('img', 'Введите корректный Url картинки') - поле с названием контейнера img, при ошибке валидации вовыводит текст 'Введите корректный Url картинки'.
    • .isURL() - функция валидации проверяющая строку img как ссылку.

Подключение промежуточного обработчика происходит локально в соответствующие машрутизаторы. Перечень всех страниц с типами запроса и машрутизаторами показан в таблице "Все страницы с типами запросами и маршрутизаторами которые обрабатываются промежуточным обработчиком courseValidators".

Все страницы с типами запросами и маршрутизаторами которые обрабатываются промежуточным обработчиком courseValidators

Название страницы Метод запроса URL-путь запроса Краткое описание
Курсы post "/courses/edit" Отправка редактируемых данных старого курса
Добавить курс post "/add" Отправка и сохранение одного курса и последующего перенаправления на страницу курсов

Интеграция промежуточного обработчика courseValidators в машрутизаторы выглядит следующим образом:

router.post('/', auth,  async (req, res) => {})

Где:

  • router.post() - метод запроса post объекта router, который принимает 3 аргумента:
    • '/' - обязательный параметр, который определяет маршрут запроса.
    • auth - необязательный параметр. Промежуточный обработчик, проверяющий сеанс пользователя.
    • async (req, res) => {} - обязательный параметр, callback-функция.

⬅️ Подробнее о контроллерах смотрите раздел Контроллеры.
⬅️ Подробнее о маршрутизаторах смотрите раздел Маршрутизация.
⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


UserMiddleware

UserMiddleware необходим для организации сесии для одного пользователя. Код предоставления сесии для одного пользователя:

module.exports = async function(req, res, next) {
    if (!req.session.user) {
        return next()
    }
    
    req.user = await User.findById(req.session.user._id)
    next()
}

Где:

  • function(req, res, next) {}) - функция промежуточного обработчика принимающая 3 аргумента: объект запроса req, объект ответа res и функцию next определяющую окончание кода промежуточного обработчика и позволяющая компилятору считывать следующий, за промежуточным обработчиком, код программы.
  • if (!req.session.user) {} - условие, которое выполняется если отсутствие сеанс пользователя.
  • req.user = await User.findById(req.session.user._id) - метод findById модели User находит пользователя по его ID из тела запроса сессий пользователей и присваивает свойству user значение этого ID пользователя.
  • next() - обязательный аргумент промежуточного обработчика, отвечающий за определение окончание кода промежуточного обработчика и позволяющий компилятору считывать дальнейший код приложения.

Подключение промежуточного обработчика UserMiddleware из файла user.js в главный файл index.js:

const UserMiddleware = require('./midlleware/user')
app.use(UserMiddleware)

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.


varMiddleware

varMiddleware необходим для присванивание значений авторизации, которые в представлениях будут организовывать условия для визуализации тех или иных данных. Код промежуточного обработчика:

module.exports = function(req, res, next) {
    res.locals.isAuth = req.session.isAuthenticated
    res.locals.csrf = req.csrfToken()
    next()
}

Где:

  • res.locals.isAuth - специальное свойство locals объекта ответа res определяющие локальный ключ isAuth.
  • req.session.isAuthenticated - флаг аутентификации, которое хранится в свойстве session объекта запроса req.
  • res.locals.csrf - специальное свойство locals объекта ответа res определяющие локальный ключ csrf.
  • req.csrfToken() - токен CSURF защиты, который приходит с объектом запроса.

Подключение промежуточного обработчика varMiddleware из файла variables.js в главный файл index.js:

const varMiddleware = require('./midlleware/variables')
app.use(UserMiddleware)

⬆️ К оглавлению раздела.
↩️ К оглавлению документации.