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

4.3 KiB
Raw Blame History

id title challengeType forumTopicId dashedName
589fc831f9fc0f352b528e77 使用 Socket.IO 进行身份验证 2 301548 authentication-with-socket-io

--description--

目前,你还无法确定连接到服务器的用户身份。 虽然 req.user 包含用户信息,但这个只在用户直接与服务器交互时产生。当用户通过 web socket 与服务器连接时,由于不存在 req 对象,我们就无法获取用户数据。 解决这个问题的方法之一是通过读取和解析请求中包含 passport session 的 cookie然后反序列化进而获取用户信息对象。 幸运的是NPM 上有可以让这个复杂的流程简单化的库。

添加 passport.socketio@~3.7.0connect-mongo@~3.2.0cookie-parser@~1.4.5 作为依赖,把它们分别赋值给 passportSocketIoMongoStorecookieParser。 同时,我们需要从之前引入的 express-session 中开辟新的内存空间, 就像这样:

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

现在我们只需要让 Socket.IO 调用它并进行相应的配置即可。 请注意,以上这些都必须放在现有的 socket 相关代码之前,而且不能放到连接的监听回调函数里。 你的服务器代码应类似于这样:

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

记得要把 keystore 加到 app 的 session 中间件。 这样,SocketIO 才知道该对哪个 session 执行此配置。


接下来,我们可以定义 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');

这样,我们可以在 console 里看到谁连接到了我们的服务器。

完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考这里的答案。

--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。

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