Chapter 36

techniques-session

kisihara.c
kisihara.c
2021.06.29に更新

セッション

HTTPセッションを使うと、複数のリクエスト間でユーザーに関する情報を保存できる。これはMVCアプリケーションでは特に便利だ。

expressで使う(デフォルト)

まず必要なパッケージをインストールしよう。TypeScriptユーザーの場合は型も導入しよう。

$ npm i express-session
$ npm i -D @types/express-session

インストールが完了したら、ミドルウェアexpress-sessionをグローバルミドルウェアとして適用する。(main.tsの中など)

import * as session from 'express-session';
// 初期化ファイルの中のどこか
app.use(
  session({
    secret: 'my-secret',
    resave: false,
    saveUninitialized: false,
  }),
);

NOTICE
デフォルトのサーバーサイドセッションストレージは本番環境向けには設計されていない。ほとんどの環境でメモリリークを起こし、単一のプロセスを超えて拡張する事はできない。デバッグ・開発用だ。詳しくは公式リポジトリにて。

secretはセッションIDクッキーの署名に使用される。単一の秘密の文字列か、複数の秘密の配列を指定するものだ。秘密の配列を指定した場合、最初の要素だけがセッションIDクッキーの署名に使用され、リクエストの署名を検証するときにすべての要素が使われる。secretは人間が簡単に解析できないランダム文字の集合である事が望ましい。

resaveオプションを有効にすると、リクエスト中にセッションが変更されていなくても、セッションストアにセッションが保存される。デフォルト値はtrueだが、将来的にデフォルト値が変更される予定なので、デフォルト値の仕様は推奨されない。

同様に、saveUnitializedオプションを有効にすると、「初期化されていない」セッションがストアに保存される。初期化されていないセッションとは、新しく作成されたが変更されていないセッションのことだ。falseを選択すると、ログインセッションの実装、サーバーのストレージ使用量の削減、またはCookieの設定に許可を求める法律への準拠に役立つ。また、falseを選択すると、クライアントがセッションを持たずに複数のリクエストを並行して行うような競合状態を回避できる

sessionミドルウェアには、他にもいくつかの引数を渡す事ができる。API documentationを参照の事。

HINT
secure:true設定を推奨する。ただし、これにはhttps対応のウェブサイトが必要となる。secureが設定されていても、HTTPでサイトにアクセスするとクッキーは設定されない。node.jsをプロキシの背後においてsecure:trueを使っている場合は、expressでtrust proxyを設定する必要がある。

これで、ルートハンドラ内からセッション値の設定や読み出しができるようになった。

@Get()
findAll(@Req() request: Request) {
  request.session.visits = request.session.visits ? request.session.visits + 1 : 1;
}

HINT
@session()デコレータは@nestjs/commonパッケージからインポートする。

Fastlyで使う

まず必要なパッケージをインストールしよう。

$ npm i fastify-secure-session

インストールが完了したら、fastify-secure-sessionプラグインを登録する。

import secureSession from 'fastify-secure-session';

// 初期化ファイルのどこか
const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  new FastifyAdapter(),
);
app.register(secureSession, {
  secret: 'averylogphrasebiggerthanthirtytwochars',
  salt: 'mq9hDxBVDbspDR6n',
});

HINT
鍵を事前生成したり(instructions)、
キーローテーションを使うこともできる。

追加オプションは公式リポジトリを参照の事。

これで、次のようにルートハンドラ内でセッション値を設定したり読み出したりできるようになった。

@Get()
findAll(@Req() request: FastifyRequest) {
  const visits = request.session.get('visits');
  request.session.set('visits', visits ? visits + 1 : 1);
}

あるいは、@session()デコレータを使って、以下のようにリクエストからセッションオブジェクトを抽出することもできる。

@Get()
findAll(@Session() session: secureSession.Session) {
  const visits = session.get('visits');
  session.set('visits', visits ? visits + 1 : 1);
}

HINT
@Session()デコレータは@nestjs/commonから、secureSession.Sessionfastify-secure-sessionパッケージからインポートされている。※import * as secureSession from 'fastify-secure-session'