💡

socket.ioに簡単な認証用ミドルウェアを実装する

に公開

socket.io、便利ですよね。

最近趣味で使うことが増えてきているのですが、不正なクライアントを防止するために認証をかける必要が出てきました。
ただ、Docsの情報が少なくて苦しみました。(Docs内で迷子になっているだけかもしれません 😇)
確かに、JWTを使う〜とかそういうのは見つかったのですが...

https://socket.io/how-to/use-with-jwt

私の場合、"クライアントとサーバー側のシークレットが一致するか否か"をチェックするだけで十分なのでわざわざこんなにコードも書きたくありませんし、なるべく依存パッケージも減らしたいです。

で、調べてみたらすぐに見つかりました

サーバー側

全体はこんな感じ:

server.js
import { logger } from 'comodern';
import { createServer } from 'http';
import { Server } from 'socket.io';
import { config } from './config';

const httpServer = createServer();
const io = new Server(httpServer);

io.use((socket, next) => {
  const secret = socket.handshake.query.secret;
  if (config.secret == socket) {
    return next();
  }
  return next(new Error('Authentication Failed'));
});

io.on('connection', (socket) => {
  logger.log(`[Socket.io] Connected from ${socket.conn.remoteAddress}`);
});

httpServer.listen(8300);

ここで認証します。


io.use((socket, next) => {
  const secret = socket.handshake.query.secret;
  if (config.secret == socket) {
    return next();
  }
  return next(new Error('Authentication Failed'));
});

見たらわかる通り、シークレットが一致するかどうかで接続の許可を判断します。

クライアント側

全体はこんな感じ:

client.js
import { io } from "socket.io-client";
import { config } from "../../config";

const socket = io(config.ws.endpoint, {
  query: {
    secret: config.ws.secret,
  },
});

socket.on("connect", () => {
  // ...
});

オプションをちょっといじくるだけです。当たり前ですが認証に失敗した場合はconnectイベントが発火しません。

ちなみに再接続時にシークレットを書き換えて再試行できます。なので 総当りができます。 ここら辺は各自うまいこと対策してください。

socket.on('reconnect_attempt', () => {
  socket.io.opts.query = {
    secret: 'foo'
  }
})

それでは。また今度。

Discussion