node.js Socket.IO 认证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4753957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Socket.IO Authentication
提问by Ryan
I am trying to use Socket.IO in Node.js, and am trying to allow the server to give an identity to each of the Socket.IO clients. As the socket code is outside the scope of the http server code, it doesn't have easy access to the request information sent, so I'm assuming it will need to be sent up during the connection. What is the best way to
我试图在 Node.js 中使用 Socket.IO,并试图允许服务器为每个 Socket.IO 客户端提供一个身份。由于套接字代码超出了 http 服务器代码的范围,因此无法轻松访问发送的请求信息,因此我假设需要在连接期间将其发送出去。最好的方法是什么
1) get the information to the server about who is connecting via Socket.IO
1) 通过 Socket.IO 向服务器获取有关谁正在连接的信息
2) authenticate who they say they are (I'm currently using Express, if that makes things any easier)
2)验证他们所说的是谁(我目前正在使用 Express,如果这让事情变得更容易)
采纳答案by Shripad Krishna
Use connect-redis and have redis as your session store for all authenticated users. Make sure on authentication you send the key (normally req.sessionID) to the client. Have the client store this key in a cookie.
使用 connect-redis 并将 redis 作为所有经过身份验证的用户的会话存储。确保在身份验证时将密钥(通常为 req.sessionID)发送给客户端。让客户端将此密钥存储在 cookie 中。
On socket connect (or anytime later) fetch this key from the cookie and send it back to the server. Fetch the session information in redis using this key. (GET key)
在套接字连接上(或以后的任何时间)从 cookie 中获取此密钥并将其发送回服务器。使用此键在 redis 中获取会话信息。(获取键)
Eg:
例如:
Server side (with redis as session store):
服务器端(以redis作为会话存储):
req.session.regenerate...
res.send({rediskey: req.sessionID});
Client side:
客户端:
//store the key in a cookie
SetCookie('rediskey', <%= rediskey %>); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
//then when socket is connected, fetch the rediskey from the document.cookie and send it back to server
var socket = new io.Socket();
socket.on('connect', function() {
var rediskey = GetCookie('rediskey'); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
socket.send({rediskey: rediskey});
});
Server side:
服务器端:
//in io.on('connection')
io.on('connection', function(client) {
client.on('message', function(message) {
if(message.rediskey) {
//fetch session info from redis
redisclient.get(message.rediskey, function(e, c) {
client.user_logged_in = c.username;
});
}
});
});
回答by Alfred
I also liked the way pusherappdoes private channels.
A unique socket id is generated and sent to the browser by Pusher. This is sent to your application (1) via an AJAX request which authorizes the user to access the channel against your existing authentication system. If successful your application returns an authorization string to the browser signed with you Pusher secret. This is sent to Pusher over the WebSocket, which completes the authorization (2) if the authorization string matches.
Pusher 会生成一个唯一的 socket id 并发送给浏览器。这通过 AJAX 请求发送到您的应用程序 (1),该请求授权用户根据您现有的身份验证系统访问通道。如果成功,您的应用程序会向浏览器返回一个使用您的 Pusher 密码签名的授权字符串。这将通过 WebSocket 发送到 Pusher,如果授权字符串匹配,则它完成授权 (2)。
Because also socket.iohas unique socket_id for every socket.
因为socket.io每个套接字也有唯一的 socket_id。
socket.on('connect', function() {
console.log(socket.transport.sessionid);
});
They used signed authorization stringsto authorize users.
他们使用签名的授权字符串来授权用户。
I haven't yet mirrored this to socket.io, but I think it could be pretty interesting concept.
我还没有将其映射到socket.io,但我认为这可能是一个非常有趣的概念。
回答by José F. Romaniello
I know this is bit old, but for future readers in addition to the approach of parsing cookie and retrieving the session from the storage (eg. passport.socketio) you might also consider a token based approach.
我知道这有点旧,但是对于未来的读者来说,除了解析 cookie 和从存储中检索会话的方法(例如,passport.socketio)之外,您还可以考虑基于令牌的方法。
In this example I use JSON Web Tokens which are pretty standard. You have to give to the client page the token, in this example imagine an authentication endpoint that returns JWT:
在这个例子中,我使用非常标准的 JSON Web Tokens。您必须向客户端页面提供令牌,在此示例中,假设有一个返回 JWT 的身份验证端点:
var jwt = require('jsonwebtoken');
// other requires
app.post('/login', function (req, res) {
// TODO: validate the actual user user
var profile = {
first_name: 'John',
last_name: 'Doe',
email: '[email protected]',
id: 123
};
// we are sending the profile in the token
var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });
res.json({token: token});
});
Now, your socket.io server can be configured as follows:
现在,您的 socket.io 服务器可以配置如下:
var socketioJwt = require('socketio-jwt');
var sio = socketIo.listen(server);
sio.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
sio.sockets
.on('connection', function (socket) {
console.log(socket.handshake.decoded_token.email, 'has joined');
//socket.on('event');
});
The socket.io-jwt middleware expects the token in a query string, so from the client you only have to attach it when connecting:
socket.io-jwt 中间件需要查询字符串中的令牌,因此从客户端您只需在连接时附加它:
var socket = io.connect('', {
query: 'token=' + token
});
I wrote a more detailed explanation about this method and cookies here.
我在这里写了有关此方法和 cookie 的更详细说明。
回答by zurfyx
Here is my attempt to have the following working:
这是我尝试进行以下工作:
- express: 4.14
- socket.io: 1.5
- passport(using sessions): 0.3
- redis: 2.6 (Really fast data structure to handle sessions; but you can use others like MongoDB too. However, I encourage you to use this for session data + MongoDB to store other persistent data like Users)
- 快递:4.14
- socket.io:1.5
- 护照(使用会话):0.3
- redis: 2.6(处理会话的数据结构非常快;但您也可以使用其他像 MongoDB 这样的结构。不过,我鼓励您将其用于会话数据 + MongoDB 来存储其他持久性数据,例如用户)
Since you might want to add some API requests as well, we'll also use httppackage to have both HTTP and Web socket working in the same port.
由于您可能还想添加一些 API 请求,我们还将使用http包让 HTTP 和 Web 套接字在同一端口工作。
server.js
服务器.js
The following extract only includes everything you need to set the previous technologies up. You can see the complete server.js version which I used in one of my projects here.
以下摘录仅包含设置先前技术所需的一切。您可以在此处查看我在我的一个项目中使用的完整 server.js 版本。
import http from 'http';
import express from 'express';
import passport from 'passport';
import { createClient as createRedisClient } from 'redis';
import connectRedis from 'connect-redis';
import Socketio from 'socket.io';
// Your own socket handler file, it's optional. Explained below.
import socketConnectionHandler from './sockets';
// Configuration about your Redis session data structure.
const redisClient = createRedisClient();
const RedisStore = connectRedis(Session);
const dbSession = new RedisStore({
client: redisClient,
host: 'localhost',
port: 27017,
prefix: 'stackoverflow_',
disableTTL: true
});
// Let's configure Express to use our Redis storage to handle
// sessions as well. You'll probably want Express to handle your
// sessions as well and share the same storage as your socket.io
// does (i.e. for handling AJAX logins).
const session = Session({
resave: true,
saveUninitialized: true,
key: 'SID', // this will be used for the session cookie identifier
secret: 'secret key',
store: dbSession
});
app.use(session);
// Let's initialize passport by using their middlewares, which do
//everything pretty much automatically. (you have to configure login
// / register strategies on your own though (see reference 1)
app.use(passport.initialize());
app.use(passport.session());
// Socket.IO
const io = Socketio(server);
io.use((socket, next) => {
session(socket.handshake, {}, next);
});
io.on('connection', socketConnectionHandler);
// socket.io is ready; remember that ^this^ variable is just the
// name that we gave to our own socket.io handler file (explained
// just after this).
// Start server. This will start both socket.io and our optional
// AJAX API in the given port.
const port = 3000; // Move this onto an environment variable,
// it'll look more professional.
server.listen(port);
console.info(` API listening on port ${port}`);
console.info(` Socket listening on port ${port}`);
sockets/index.js
套接字/ index.js
Our socketConnectionHandler, I just don't like putting everything inside server.js (even though you perfectly could), especially since this file can end up containing quite a lot of code pretty quickly.
我们的socketConnectionHandler, 我只是不喜欢把所有东西都放在 server.js 中(即使你完全可以),特别是因为这个文件很快就会包含相当多的代码。
export default function connectionHandler(socket) {
const userId = socket.handshake.session.passport &&
socket.handshake.session.passport.user;
// If the user is not logged in, you might find ^this^
// socket.handshake.session.passport variable undefined.
// Give the user a warm welcome.
console.info(`?? New connection: ${userId}`);
socket.emit('Grettings', `Grettings ${userId}`);
// Handle disconnection.
socket.on('disconnect', () => {
if (process.env.NODE_ENV !== 'production') {
console.info(`?? Disconnection: ${userId}`);
}
});
}
Extra material (client):
额外材料(客户):
Just a very basic version of what the JavaScript socket.io client could be:
只是 JavaScript socket.io 客户端的一个非常基本的版本:
import io from 'socket.io-client';
const socketPath = '/socket.io'; // <- Default path.
// But you could configure your server
// to something like /api/socket.io
const socket = io.connect('localhost:3000', { path: socketPath });
socket.on('connect', () => {
console.info('Connected');
socket.on('Grettings', (data) => {
console.info(`Server gretting: ${data}`);
});
});
socket.on('connect_error', (error) => {
console.error(`Connection error: ${error}`);
});
References:
参考:
I just couldn't reference inside the code, so I moved it here.
我只是无法在代码内部引用,所以我把它移到了这里。
1: How to set up your Passport strategies: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
1:如何设置您的 Passport 策略:https: //scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
回答by Blade1336
This article (http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/) shows how to
这篇文章 ( http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/) 展示了如何
- store sessions of the HTTP server in Redis (using Predis)
- get these sessions from Redis in node.js by the session id sent in a cookie
- 在 Redis 中存储 HTTP 服务器的会话(使用 Predis)
- 通过 cookie 中发送的会话 ID 从 node.js 中的 Redis 获取这些会话
Using this code you are able to get them in socket.io, too.
使用此代码,您也可以在 socket.io 中获取它们。
var io = require('socket.io').listen(8081);
var cookie = require('cookie');
var redis = require('redis'), client = redis.createClient();
io.sockets.on('connection', function (socket) {
var cookies = cookie.parse(socket.handshake.headers['cookie']);
console.log(cookies.PHPSESSID);
client.get('sessions/' + cookies.PHPSESSID, function(err, reply) {
console.log(JSON.parse(reply));
});
});
回答by onplanner
use session and redis between c/s
在 c/s 之间使用 session 和 redis
// server side
// 服务器端
io.use(function(socket, next) {
console.log(socket.handshake.headers.cookie); // get here session id and match from redis session data
next();
});
回答by dominic
this should do it
这应该这样做
//server side
io.sockets.on('connection', function (con) {
console.log(con.id)
})
//client side
var io = io.connect('http://...')
console.log(io.sessionid)

