Отправить пользовательские данные вместе с handshakeData в socket.io?

Итак, у меня есть приложение, работающее с узлом js, с socket.io в качестве бэкэнда и обычным javascript в качестве внешнего интерфейса. В моем приложении есть система входа в систему, которая в настоящее время просто заставляет клиента отправлять свои данные для входа, как только он подключается.

Теперь я подумал, что было бы намного лучше отправить данные для входа вместе с данными рукопожатия, чтобы я мог напрямую входить в систему при подключении (а не после установления соединения), соответственно отказываться от авторизации, когда данные для входа недействительны.

Я думаю, что было бы лучше поместить мои дополнительные данные в заголовочную часть рукопожатия, так что есть идеи, как я могу это сделать? (Без необходимости изменять socket.io, если это возможно, но если это единственный способ, которым я могу с этим жить)


person Wingblade    schedule 06.12.2012    source источник


Ответы (7)


Как указано во многих комментариях ниже, API Socket.IO изменился в их выпуске 1.0. Аутентификация теперь должна выполняться с помощью функции промежуточного программного обеспечения, см. «Различия аутентификации» @ http://socket.io/docs/migrating-from-0-9/#authentication-differences. Я включу свой оригинальный ответ для тех, кто застрял на ‹ 1.0, поскольку старые документы, похоже, ушли.

1.0 и выше:

Сторона клиента:

//The query member of the options object is passed to the server on connection and parsed as a CGI style Querystring.
var socket = io("http://127.0.0.1:3000/", { query: "foo=bar" });

Сторона сервера:

io.use(function(socket, next){
    console.log("Query: ", socket.handshake.query);
    // return the result of next() to accept the connection.
    if (socket.handshake.query.foo == "bar") {
        return next();
    }
    // call next() with an Error if you need to reject the connection.
    next(new Error('Authentication error'));
});

До 1.0

Вы можете передать query: param во втором аргументе для подключения () на стороне клиента, который будет доступен на сервере в методе авторизации.

Я только что тестировал это. На клиенте у меня есть:

var c = io.connect('http://127.0.0.1:3000/', { query: "foo=bar" });

На сервере:

io.set('authorization', function (handshakeData, cb) {
    console.log('Auth: ', handshakeData.query);
    cb(null, true);
});

Вывод на сервере тогда выглядел так:

:!node node_app/main.js
   info  - socket.io started
Auth:  { foo: 'bar', t: '1355859917678' }

Обновлять

3.х и выше

Вы можете передать полезную нагрузку аутентификации, используя параметр auth в качестве второго аргумента для connect() на стороне клиента.

Сторона клиента:

io.connect("http://127.0.0.1:3000/", {
    auth: {
      token: "AuthToken",
    },
  }),

На стороне сервера вы можете получить к нему доступ, используя socket.handshake.auth.token

Сторона сервера:

io.use(function(socket, next){
    console.log(socket.handshake.auth.token)
    next()
});
person Alex Wright    schedule 18.12.2012
comment
Спасибо! Именно то, что я хотел! +1 - person Wingblade; 20.12.2012
comment
Можно ли также отправить клиенту некоторые данные обратно с помощью рукопожатия? - person Rob Fox; 21.05.2013
comment
@RobFox IIRC Роб Я так не думаю, но вы можете написать на канал сразу после его создания, и это будет первое, что увидит подключающийся клиент. - person Alex Wright; 21.05.2013
comment
Отлично. Это очень помогло мне. Спасибо. - person Art Geigel; 27.08.2013
comment
Стоит отметить, что это подразумевает отправку данных в виде строки запроса, что не рекомендуется, если эти данные должны быть секретными (например, пароли или токены авторизации). - person Facundo Olano; 11.10.2014
comment
@FacundoOlano, как можно было бы добиться этого по-другому? Независимо от строки запроса, postvars или специального заголовка, токен доступен для перехвата, если https не используется. Но мне бы очень хотелось узнать ваше решение для смягчения такой атаки MIM. - person japrescott; 06.01.2015
comment
@japrescott вы не можете ожидать никакой безопасности без https; но даже с https отправка токенов в строке запроса не рекомендуется. Мой обходной путь — отправить сообщение аутентификации и поместить токен в тело сообщения. Я объяснил это здесь - person Facundo Olano; 27.01.2015
comment
@AlexWright: Как я могу передать 2 параметра с опцией запроса? Заранее спасибо.! - person Pritam; 18.03.2015
comment
@Pritam Вы бы просто добавили второй параметр в строку запроса (в примере foo=bar). Таким образом, примером с двумя параметрами может быть foo=bar&baz=whatever. Рассмотрите возможность использования encodeURIComponent() для кодирования значения, если оно содержит что-либо недопустимое или ожидаемое в URL-адресе. - person Alex Wright; 18.03.2015
comment
@AlexWright ваш ответ не работает с более новыми версиями socket.io, не могли бы вы обновить его, чтобы отразить мой ответ (stackoverflow.com/a/ 27605655/2866570) - person zaynetro; 07.05.2015
comment
Метод .set() устарел - person Ravi; 24.05.2015
comment
Также стоит отметить, что вы можете использовать объект вместо закодированной строки. например: вместо { query: "foo=bar" } вы можете сделать { query: { foo: "bar" } } - person Deminetix; 09.12.2015
comment
@Deminetix Возможно, это только после изменения API? Я попробовал это на экземпляре до версии 1.0, и он сломался при попытке .split на &. - person Alex Wright; 09.12.2015
comment
@AlexWright Да, это последняя версия, установленная вчера - person Deminetix; 10.12.2015

Теперь это было изменено в v1.0.0. См. документацию по миграции.

в основном,

io.set('authorization', function (handshakeData, callback) {
  // make sure the handshake data looks good
  callback(null, true); // error first, 'authorized' boolean second 
});

становится:

  io.use(function(socket, next) {
  var handshakeData = socket.request;
  // make sure the handshake data looks good as before
  // if error do this:
    // next(new Error('not authorized');
  // else just call next
  next();
});
person slupek2013    schedule 24.09.2014
comment
как мне получить поле query из поля socket.request на стороне сервера? - person Harry Moreno; 26.02.2015
comment
@HarryMoreno Используйте socket.request._query - person Ciaran; 04.03.2015

Для socket.io v1.2.1 используйте это:

io.use(function (socket, next) {
  var handshake = socket.handshake;
  console.log(handshake.query);
  next();
});
person zaynetro    schedule 22.12.2014

Это мой код для отправки данных запроса на сервер nodejs и server.io.

var socket = io.connect(window.location.origin, { query: 'loggeduser=user1' });

io.sockets.on('connection', function (socket) {
    var endp = socket.manager.handshaken[socket.id].address;
    console.log("query... " + socket.manager.handshaken[socket.id].query.user);
}
person user2969994    schedule 29.03.2014
comment
Это было лучшим решением. Но socket.manager.handshaken[socket.id].query.user должно быть socket.manager.handshaken[socket.id].query.loggeduser - person Valter Lorran; 16.07.2014
comment
Вероятно, это зависит от версии. Я мог заставить его работать только с socket.handshake.query.userOrWhatever - person makc; 13.09.2014

Возможно, API изменился, но я сделал следующее, чтобы получить дополнительную информацию на сервер.

// client
io.connect('localhost:8080', { query: 'foo=bar', extra: 'extra'});

// server
io.use(function(sock, next) {
  var handshakeData = sock.request;
  console.log('_query:', handshakeData._query);
  console.log('extra:', handshakeData.extra);
  next();
});

отпечатки

_query: { foo: 'bar',
  EIO: '3',
  transport: 'polling',
  t: '1424932455409-0' }
extra: undefined

Если кто-нибудь знает, как получить данные от клиента к серверу через рукопожатие, которого нет в параметрах запроса, дайте мне знать, пожалуйста.

Обновить Позже у меня возникли проблемы с этим синтаксисом

io.connect('localhost:8080?foo=bar');

это то, что я сейчас использую.

person Harry Moreno    schedule 26.02.2015

Старый поток, но если вы храните свой токен / идентификатор сеанса jwt в файлах cookie сеанса (стандартный материал), он все равно передается на сервер по умолчанию при выполнении рукопожатия (socket.io-client), как я заметил. Есть ли что-то неправильное в том, чтобы просто получить информацию об аутентификации для рукопожатия (через промежуточное ПО или on.connection) через файл cookie? например.

io.on('connection', function(socket) {
  // assuming base64url token
  const cookieStr = socket.handshake.headers.cookie
  const matchRes =
    cookieStr == null
      ? false
      : cookieStr.match(/my-auth-token=([a-zA-Z0-9_.-]+)/)
  if (matchRes) {
    // verify your jwt...
    if ( tokenIsGood(matchRes[1]) {
      // handle authenticated new socket
    } else {
      socket.emit('AUTH_ERR_LOGOUT')
      socket.disconnect()
    }
  } else {
    socket.emit('AUTH_ERR_LOGOUT')
    socket.disconnect()
  }
}

Я использую это сейчас для проекта, и он работает нормально.

person KM3    schedule 26.01.2019

Я обнаружил небольшую проблему с просмотром .loggeduser

io.sockets.on('connection', function (socket) {
    var endp = socket.manager.handshaken[socket.id].address;
    console.log("query... " + socket.manager.handshaken[socket.id].query.loggeduser);
                                                                         // ↑ here
}
person user3678015    schedule 27.05.2014