답변:
connect-redis를 사용하고 인증 된 모든 사용자에 대한 세션 저장소로 redis를 사용합니다. 인증시 클라이언트에 키 (일반적으로 req.sessionID)를 보내야합니다. 클라이언트가이 키를 쿠키에 저장하도록합니다.
소켓 연결시 (또는 나중에 언제든지) 쿠키에서이 키를 가져와 서버로 다시 보냅니다. 이 키를 사용하여 redis에서 세션 정보를 가져옵니다. (GET 키)
예 :
서버 측 (redis를 세션 저장소로 사용) :
req.session.regenerate...
res.send({rediskey: req.sessionID});
고객 입장에서:
//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});
});
서버 측:
//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;
});
}
});
});
GetCookie
자바 스크립트 기능입니다.
또한 pusherapp 이 비공개 채널을 수행 하는 방식이 마음에 들었습니다 .
고유 한 소켓 ID가 생성되어 Pusher에 의해 브라우저로 전송됩니다. 이는 사용자가 기존 인증 시스템에 대해 채널에 액세스 할 수 있도록 권한을 부여하는 AJAX 요청을 통해 애플리케이션 (1)으로 전송됩니다. 성공하면 애플리케이션은 Pusher 비밀로 서명 된 브라우저에 인증 문자열을 반환합니다. 이는 WebSocket을 통해 Pusher로 전송되며, 인증 문자열이 일치하면 인증 (2)을 완료합니다.
또한 socket.io
모든 소켓에 대해 고유 한 socket_id가 있기 때문 입니다.
socket.on('connect', function() {
console.log(socket.transport.sessionid);
});
그들은 사용자를 인증하기 위해 서명 된 인증 문자열 을 사용 했습니다 .
나는 아직 이것을에 미러링하지 않았지만 socket.io
꽤 흥미로운 개념이 될 수 있다고 생각합니다.
나는 이것이 조금 오래되었다는 것을 알고 있지만, 미래의 독자를 위해 쿠키를 구문 분석하고 저장소 (예 : passport.socketio ) 에서 세션을 검색하는 방법 외에도 토큰 기반 접근 방식을 고려할 수 있습니다.
이 예에서는 꽤 표준 인 JSON 웹 토큰을 사용합니다. 클라이언트 페이지에 토큰을 제공해야합니다.이 예에서는 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: 'john@doe.com',
id: 123
};
// we are sending the profile in the token
var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });
res.json({token: token});
});
이제 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');
});
socket.io-jwt 미들웨어는 쿼리 문자열에서 토큰을 예상하므로 클라이언트에서는 연결할 때만 연결하면됩니다.
var socket = io.connect('', {
query: 'token=' + token
});
여기 에이 방법과 쿠키에 대한 자세한 설명을 썼습니다 .
다음은 다음과 같은 작업을 시도합니다.
일부 API 요청도 추가 할 수 있으므로 http 패키지를 사용 하여 동일한 포트에서 HTTP 및 웹 소켓이 모두 작동하도록 할 것입니다.
다음 추출에는 이전 기술을 설정하는 데 필요한 모든 것이 포함되어 있습니다. 여기 에서 내 프로젝트 중 하나에서 사용한 완전한 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}`);
우리 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}`);
}
});
}
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}`);
});
코드 내부를 참조 할 수 없어서 여기로 옮겼습니다.
1 : Passport 전략 설정 방법 : https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
이 문서 ( http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/ )에서는 방법을 보여줍니다.
이 코드를 사용하면 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));
});
});
c / s 사이에 세션 및 redis 사용
// 서버 측
io.use(function(socket, next) {
console.log(socket.handshake.headers.cookie); // get here session id and match from redis session data
next();
});
이것은 그것을해야한다
//server side
io.sockets.on('connection', function (con) {
console.log(con.id)
})
//client side
var io = io.connect('http://...')
console.log(io.sessionid)