freeCodeCamp/curriculum/challenges/ukrainian/06-quality-assurance/advanced-node-and-express/authentication-with-socket....

7.2 KiB
Raw Blame History

id title challengeType forumTopicId dashedName
589fc831f9fc0f352b528e77 Автентифікація за допомогою Socket.IO 2 301548 authentication-with-socket-io

--description--

Наразі ви не можете визначити, хто підключений до вашого веб-сокету. Хоча й req.user містить об'єкт "користувач", проте тільки тоді, коли ваш користувач взаємодіє з веб-сервером, тоді ж як до веб-сокетів у вас немає req (запиту), а, як наслідок, немає і даних користувача. Одним зі способів розв'язання проблеми відсутності інформації про те, хто підключений до вашого веб-сокету, є застосування синтаксичного аналізу та декодування файлів cookie, які містять сесію паспорту, далі - отриманні дані десеріалізуються задля отримання об'єкту "користувач". На щастя, NPM має спеціальний пакет для цього, який перетворює колись складну задачу на щось просте!

Додайте passport.socketio@~3.7.0, connect-mongo@~3.2.0 та cookie-parser@~1.4.5 як залежності та встановіть(require) їх як passportSocketIo, MongoStore та cookieParser відповідно. Крім того, нам потрібно ініціалізувати нове сховище пам'яті з express-session, яке ми вже потребували (required). Воно повинно мати такий вигляд:

const MongoStore = require('connect-mongo')(session);
const URI = process.env.MONGO_URI;
const store = new MongoStore({ url: URI });

Тепер треба лише вказати Socket.IO використовувати його та встановити налаштування. Переконайтеся, що його додано перед наявним кодом сокета, а не в цьому слухачі підключення. На вашому сервері це повинно мати такий вигляд:

io.use(
  passportSocketIo.authorize({
    cookieParser: cookieParser,
    key: 'express.sid',
    secret: process.env.SESSION_SECRET,
    store: store,
    success: onAuthorizeSuccess,
    fail: onAuthorizeFail
  })
);

Зауважте, що налаштування автентифікації Passport для Socket.IO є дуже подібним до налаштування проміжного програмного забезпечення session для API. Це пояснюється тим, що вони призначені для одного методу автентифікації: отримати id сесії від файлів cookie та перевірити його.

Раніше, при налаштуванні проміжного програмного забезпечення session, ми не встановлювали безпосередньо назву файлів cookie для сесії (key). Це пояснюється тим, що пакет session використовував значення за замовчуванням. Тепер, коли додано інший пакет, який потребує доступу до того самого значення файлів cookies, треба чітко встановити значення key в обох об'єктах конфігурації.

Обов'язково виконайте додавання key з назвою файлів cookie до проміжного програмного забезпечення session, яке збігається з ключем Socket.IO. Також додайте посилання store на налаштування, поруч із якими ми пропишемо saveUninitialized: true. Необхідно вказати Socket.IO до якої сесії прив'язуватися.


Тепер слід визначити функції зворотного зв'язку success та fail:

function onAuthorizeSuccess(data, accept) {
  console.log('successful connection to socket.io');

  accept(null, true);
}

function onAuthorizeFail(data, message, error, accept) {
  if (error) throw new Error(message);
  console.log('failed connection to socket.io:', message);
  accept(null, false);
}

Об'єкт "користувач" тепер має доступ у вашому сокет-об'єкті як socket.request.user. Тепер, наприклад, ви можете додати таке:

console.log('user ' + socket.request.user.name + ' connected');

Це дозволить увійти у підключену консоль серверу!

Відправте сторінку, якщо все було виконано правильно. Якщо сталась якась помилка, то можна перевірити проєкт до цього етапу тут .

--hints--

passport.socketio має бути залежністю.

(getUserInput) =>
  $.get(getUserInput('url') + '/_api/package.json').then(
    (data) => {
      var packJson = JSON.parse(data);
      assert.property(
        packJson.dependencies,
        'passport.socketio',
        'Your project should list "passport.socketio" as a dependency'
      );
    },
    (xhr) => {
      throw new Error(xhr.statusText);
    }
  );

cookie-parser має бути залежністю.

(getUserInput) =>
  $.get(getUserInput('url') + '/_api/package.json').then(
    (data) => {
      var packJson = JSON.parse(data);
      assert.property(
        packJson.dependencies,
        'cookie-parser',
        'Your project should list "cookie-parser" as a dependency'
      );
    },
    (xhr) => {
      throw new Error(xhr.statusText);
    }
  );

passportSocketIo має правильно виконуватися (required).

(getUserInput) =>
  $.get(getUserInput('url') + '/_api/server.js').then(
    (data) => {
      assert.match(
        data,
        /require\((['"])passport\.socketio\1\)/gi,
        'You should correctly require and instantiate "passport.socketio"'
      );
    },
    (xhr) => {
      throw new Error(xhr.statusText);
    }
  );

passportSocketIo слід належним чином налаштувати.

(getUserInput) =>
  $.get(getUserInput('url') + '/_api/server.js').then(
    (data) => {
      assert.match(
        data,
        /io\.use\(\s*\w+\.authorize\(/,
        'You should register "passport.socketio" as socket.io middleware and provide it correct options'
      );
    },
    (xhr) => {
      throw new Error(xhr.statusText);
    }
  );

--solutions--

/**
  Backend challenges don't need solutions, 
  because they would need to be tested against a full working project. 
  Please check our contributing guidelines to learn more.
*/