Files
2022-01-20 20:30:18 +01:00

6.0 KiB

id, title, challengeType, forumTopicId, dashedName
id title challengeType forumTopicId dashedName
589fc831f9fc0f352b528e77 Socket.IOによる認証 2 301548 authentication-with-socket-io

--description--

今の時点で、誰がウェブソケットに接続しているかを判断することはできません。 req.user にはユーザーオブジェクトが含まれていますが、そうなっているのはユーザーがウェブサーバーとやり取りするときだけであり、ウェブソケットでは req (リクエスト) がないため、ユーザーデータはありません。 誰がウェブソケットに接続しているのかを知るための方法の 1 つとして、Passport セッションを含む Cookie を解析してデコードした後、デシリアライズしてユーザーオブジェクトを取得することができます。 幸い、 NPM にはまさにこのためのパッケージがあり、複雑な作業をシンプルにしてくれます!

passport.socketio@~3.7.0connect-mongo@~3.2.0 および cookie-parser@~1.4.5 を依存関係として追加し、それらをそれぞれ passportSocketIoMongoStore および cookieParser として require してください。 また、前に require した express-session から、新しいメモリストアを初期化する必要があります。 次のようになります。

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
  })
);

Socket.IO の Passport 認証の設定は、API の session ミドルウェアの設定方法によく似ています。 これは、同じ認証方式の使用を意図しているためです。つまり、Cookie からセッション id を取得して検証します。

前に session ミドルウェアを設定したときは、セッションの Cookie 名 (key) を明示的に設定してはいませんでした。 これは、session パッケージでデフォルト値を使用していたためです。 これで、Cookie から同じ値にアクセスする必要がある別のパッケージが追加されました。両方の設定オブジェクトへ明示的に key の値を設定する必要があります。

Socket.IO キーに一致する session ミドルウェアに、key と Cookie 名を追加してください。 また、saveUninitialized: true を設定した近くで、store 参照をオプションに追加してください。 これは、どのセッションに関連付けるかを Socket.IO に伝えるために必要です。


次に、successfail コールバック関数を定義します。

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 を適切に require する必要があります。

(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.
*/