Node.js(Express)+Redisで簡単にセッション管理を行う方法

Node.jsとExpressにおけるCookieを利用したセッション管理を行う方法を紹介します。

スポンサーリンク

express-sessionを利用する

ExpressでCookieによるセッション管理を行う場合に利用されるモジュールは以下の2つです。

モジュールセッションデータの保存場所
express-sessionサーバー側のストレージ
(オンメモリ/外部ストレージ)
cookie-sessionCookie

今回は以下の理由からexpress-sessionを採用することにします。

  • Cookie内には少量の単純なデータ(プリミティブな値)のみしか保存できない
  • セッションデータがブラウザから閲覧出来てしまう

express-session+Redisを実装する

それでは実装例を紹介します。express-sessionはデフォルトではサーバーメモリ上でセッションデータを保管しますが、実際の環境での稼動向きではないため通常外部ストレージを利用します。

今回はRedisを導入しますが、動作検証だけしたい方はストレージなしでも稼働確認できるので以下の事前準備はスキップして問題ありません。

(事前準備)Redisの用意

まずは事前準備としてRedisをDockerコンテナで準備します。
以下のdocker-compose.yamlファイルを作成し、docker-compose up -dコマンドを実行してコンテナを起動します。

version: '3.8'

services:
  redis:
    image: redis:latest
    restart: always
    ports:
      - 6379:6379

必要なモジュールのインストール

実装に必要なモジュールをインストールします。

npm i express-session
# redisを使って実装を行う人
npm i express-session redis connect-redis
# さらにTypescriptを利用している人は追加で以下のコマンドを実行
npm i -D @types/express-session @types/connect-redis

express-sessionの利用

express-sessionはsessionミドルウェアを利用することでセッションを簡単に管理することが出来ます。

import express from 'express';
import session from 'express-session';
import redis from 'redis';

const RedisStore = require('connect-redis')(session);
const redisClient = redis.createClient('redis://localhost:6379');

const app = express();

app.use(
  session({
    name: 'mockSessionId',
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: false,
    store: new RedisStore({ client: redisClient }),
    cookie: {
      secure: false,
      httpOnly: false,
    },
  })
);

オプションの概要は以下の通りです。

オプション説明
nameセッションIDの名前(デフォルトではconnect.sid)
secretCookieの署名に利用するキー
クライアントには[セッションID].[secretを利用した署名]の値が返される
resaveリクエスト中にセッションデータが書き換えられなかったとしてもストレージに保存するか。
saveUninitialized初期化されていない(何も入っていない)セッションに値を入れてストレージにほぞんするか
storeセッションデータを保管するストレージを指定する。
指定しない場合はオンメモリで管理される。
cookieCookieに関するオプション。

これで基本的な準備は完了です。

動作確認

それでは実際に動作を確かめてみます。サンプルとしてexpresssessionに掲載されている例をredis対応したものを使用します。
ソースコードはこちらに掲載しています。

GitHub - daiki0623/express-simple-session: Expressによるシンプルなセッション管理の実装です
Expressによるシンプルなセッション管理の実装です. Contribute to daiki0623/express-simple-session development by creating an account on GitHub.

リクエストを受けるとセッションを生成し、セッションデータとして各ユーザーのリクエスト回数を記録してレスポンスとして返却するというシンプルなアプリケーションです。

初回リクエスト

まずはシンプルに初回リクエストを送ってみます。
レスポンスに”you viewed this page 1 times”が返ってきました。

% curl -v http://localhost:3000/foo

*   Trying 127.0.0.1:3000...
・・・ 
< HTTP/1.1 200 OK
・・・
< Set-Cookie: mockSessionId=s%3AKq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj.ODOZ3MifiQcMVp0CYjA7v4XrYtuqhOHRsD2pcs0DjaE; Path=/
・・・
you viewed this page 1 times

レスポンスヘッダーにはSet-Cookieに署名付きのセッションID(Kq…PVj)が格納されていることが確認できます。

redisの中も確認してみましょう。セッションIDがキーとして格納されていることが確認できます。
セッションデータにはアプリケーションへのリクエスト回数viewが格納されている事が確認できます。

root@4d7c8780bc68:/data# redis-cli
127.0.0.1:6379> keys *
1) "sess:Kq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj"

127.0.0.1:6379> get sess:Kq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj
"{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":false,\"path\":\"/\"},\"views\":{\"/foo\":1}}"

Cookieをセットして2回目のリクエスト

続いて2回目のリクエストを行います。ブラウザでは通常送られたCookieを自動で保存して同じドメインに対するリクエストに対しては保存したCookieをセットしてリクエストが行われます。

今はcurlでリクエストを行っているので手動でCookieをセットしてリクエストしてみます。

% curl -b "mockSessionId=s%3AKq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj.ODOZ3MifiQcMVp0CYjA7v4XrYtuqhOHRsD2pcs0DjaE" http://localhost:3000/foo

・・・
you viewed this page 2 times

レスポンスのリクエスト回数が1から2に変化しました。これはサーバー側がリクエストCookieのセッションIDを理解して、redisのセッションデータを参照して状態を更新したことになります。

redis内を確認するとしっかりとviewsが1から2に更新されていることがわかります。

127.0.0.1:6379> get sess:Kq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj
"{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":false,\"path\":\"/\"},\"views\":{\"/foo\":2}}"

Cookieをセットしないで3回目のリクエスト

では最後にCookieをセットしないで3回目のリクエストを行ってみます。
レスポンスのリクエスト回数は3ではなく1となってしまいました。レスポンスヘッダーのSet-Cookieにも異なるセッションIDが振られています。

% curl -v http://localhost:3000/foo
*   Trying 127.0.0.1:3000...
・・・
< HTTP/1.1 200 OK
・・・
< Set-Cookie: mockSessionId=s%3AdSTw4B3PhdGNukAEoRxUCCxMPtdk35No.q5r%2BeI%2FqjfUCqRgSKrxKWDQuD1NHvwLqtzgglN2%2BbyY; Path=/
・・・
you viewed this page 1 times

これはCookieをセットしないでリクエストしたためにサーバー側は新しいユーザーのリクエストだと判断して新規のセッションを生成したことになります。

redisを確認しても新しいセッションが生成されていることが確認できます。

127.0.0.1:6379> keys *
1) "sess:dSTw4B3PhdGNukAEoRxUCCxMPtdk35No"
2) "sess:Kq861ZrP5PX_qLyE0TuAqJJcE3qN1PVj"

まとめ

以上のようにexpress-sessionを利用することでExpressアプリケーションでセッション管理を簡単に実装することができることを紹介しました。

今回はストレージとしてredisを利用しましたが、その他のストレージも利用できるのでご自身の環境に合わせてカスタマイズしてください。

コメント