[Nodejs / Socket.io] 소켓 통신 및 사용자 인증

[Nodejs / Socket.io] 소켓 통신 및 사용자 인증

사용자는 jwt, 관리자는 session을 사용하여 passport에 로그인하게 해놓은 상태에서 socket.io 라이브러리를 이용해 소켓 통신을 구현하려 한다.

passport와 socket.io를 연동시키려면 passport.socketio 라이브러리를, jwt 인증을 하려면 socket.handshake.headers.authorization 속성을 사용하면 된다.

Server Code

// socket.js const passportSocketIo = require("passport.socketio"); const { decodeToken } = require(`${process.env.PWD}/middleware/auth`); const dbModule = require(`${process.env.PWD}/database`)(); const dbConnection = dbModule.init(); dbModule.db_open(dbConnection); module.exports = (server, session) => { const io = require('socket.io')(server); const FileStore = require("session-file-store")(session); io.use(passportSocketIo.authorize({ cookieParser: require('cookie-parser'), key: 'express.sid', secret: process.env.COOKIE_SECRET, store: new FileStore(), success: onAuthorizeSuccess, fail: onAuthorizeFail, })); function onAuthorizeSuccess(data, accept){ accept(null, true); } function onAuthorizeFail(data, message, error, accept){ accept(null, false); } var userio = io.of('/user'), managerio = io.of('/manager'); userio.on('connection', (socket) => { // 인증 과정 try { // jwt가 header로 왔는지 확인하여 user인지 판별 user = decodeToken(socket.handshake.headers.authorization.split('Bearer ')[1]); console.log('user login', user); } catch { // 인증 실패 socket.disconnect(0); } // 사용자 이동 요청 socket.on('move_request', (req) => { //req.outside_id console.log(req); var sql = "INSERT INTO outside_request VALUES (NULL, ?, ?, ?, ?, ?) "; dbConnection.query(sql, [user.tag, parseInt(req.outside_id), nowDateTime(), null, null], (err, rows) => { if(err) { console.log(err); } }); managerio.emit('user2manager', {event: 'move_request', user, ...req}); }); // 사용자 위치 보고 socket.on('location_report', (req) => { //req.beacon_id, req.time console.log(req); managerio.emit('user2manager', {event: 'location_report', user, ...req}); }); }); managerio.on('connection', (socket) => { // 인증 과정 if(socket.request.user.logged_in) { // session login(관리자 로그인) 성공 시 var { salt, enc_pwd, ...manager } = socket.request.user; console.log('manager login', manager); } else { // 인증 실패 socket.disconnect(0); } }); return io; };

사용자와 관리자를 각각의 userio , managerio namespace로 나눈다.

user

userio 로 connection 이벤트가 발생하면, socket 의 handshake.headers.authorization 속성으로 jwt 토큰을 읽어오고, client가 누구인지 식별한다.

jwt 토큰을 읽어오는데 실패하면 연결을 종료한다.

manager

const passportSocketIo = require("passport.socketio"); const io = require('socket.io')(server); const FileStore = require("session-file-store")(session); io.use(.authorize({ cookieParser: require('cookie-parser'), key: 'express.sid', secret: process.env.COOKIE_SECRET, store: new FileStore(), success: onAuthorizeSuccess, fail: onAuthorizeFail, }));

socket.io와 passport를 연동시키기 위해 먼저 setting 한다.

session-memory-store 를 사용하여 세션을 메모리에 저장하면 사용 불가능하다니 참고하자.

로그인에 성공하면 onAuthorizeSuccess 가, 실패하면 onAuthorizeFail 가 콜백함수로 호출된다.

managerio 로 connection 이벤트가 발생하면, socket 의 socket.request.user.logged_in 속성 passport 상에 로그인 되어있는지 식별할 수 있다.

로그인이 되어있지 않다면 연결을 종료한다.

Client Code

user 연결

user socket test user socket page 이동 요청 (move_request) 위치 보고 (location_report) $(function () { const socket = io('/user', { transportOptions: { polling: { extraHeaders: { Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0YWciOiJ0ZXN0IiwibmFtZSI6IuycoOyggO2FjOyKpO2KuCIsInJhbmsiOiJraW5nIiwicm9vbV9pZCI6bnVsbCwiZG9vbV9pZCI6bnVsbCwiaWF0IjoxNjMyOTAyNDAwLCJleHAiOjE2NjQ0Mzg0MDB9.hfKpCcJcNMk7FW8Aqn7SIabNthrgvMtJc8He0F7ZInI" }, } } }); $('#move_request').submit(function(e) { e.preventDefault(); socket.emit('move_request', {outside_id: $('#a').val()}); return false; }); $('#location_report').submit(function(e) { e.preventDefault(); socket.emit('location_report', {beacon_id: $('#b').val(), time: new Date()}); return false; }); });

소켓 연결 시 '/user' 로 네임스페이스 지정해 주고, transportOptions.polling.extraHeaders 로 헤더를 설정할 수 있다.

manager 연결

manager socket test manager socket page $(function () { const socket = io('/manager'); socket.on('user2manager', function(msg) { $('#messages').append($('

  • ').text(JSON.stringify(msg))); }); });

    결과

    from http://mskim9967.tistory.com/88 by ccl(S) rewrite - 2021-10-01 13:26:17