Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Next.jsとUpstash Redisで実現する安全なセッション管理の完全ガイド

本ガイドでは、Upstash Redisを使用したNext.jsアプリケーションにおけるセッション管理について解説します。Webアプリケーションにおける「セッション」とは何か、なぜRedisがセッション管理に最適なのか、Upstash Redisデータベースのセットアップ方法、そして実際にNext.jsアプリケーションへ統合する手順まで、順を追って学んでいきましょう。

「セッション」とは何か?

Webアプリケーションにおける「セッション」とは、一定時間内の複数のHTTPリクエストにわたって、ユーザーとアプリケーションのやり取りの状態(ステート)を維持するための一時的なサーバー側ストレージの仕組みです。

HTTPはステートレスなプロトコルです。つまり、各リクエストは独立しており、以前のやり取りを「記憶」していません。セッションを使うことで、サーバーは認証状態、ユーザーの設定、サイト上でのユーザーの活動履歴など、ユーザー固有のデータを追跡・保存できるようになります。

セッションは通常、クライアント側(多くの場合Cookie)に一意のセッションIDを保存することで機能します。サーバーはこのIDを使用して、ユーザーがサイトにアクセスするたびに、Redisなどのセッションストレージから該当ユーザーのセッションデータを取得します。

Webアプリケーションにおけるセッションは、以下のようなユーザー操作や状態管理を扱うのに非常に有効です。

  • ユーザー認証: セッションによってユーザーを認証し、ページをまたいでも、さらにはページ更新後もログイン状態を記憶できます。
  • パーソナライゼーション: ユーザーの設定や認証状態などのデータを、サーバーが保存・取得できるようになります。
  • セキュリティ: 適切なセッション管理は、CSRF対策や、権限のないユーザーによる制限領域へのアクセス防止など、アプリケーションのセキュリティ向上につながります。

なぜセッション管理にRedisなのか?

Redisをセッションストアとして採用すべき理由は多数あります。Redisの構造に由来する主なメリットを見てみましょう。

  • データ構造: Redisはインメモリ型のキーバリューストアです。キーバリューペアはハッシュとして保存でき、ハッシュとはフィールドと値のペアの集合として構造化されたレコード型です。この構造は、ユーザー名やユーザー設定といったセッションデータを、ユーザーセッションごとのハッシュ内にキーバリュー形式で保持するという、セッション管理のデータ形式に完璧に適合します。

  • データの有効期限: Redisには期限切れデータを自動削除する組み込み機能があります。これにより、Webアプリケーションはユーザーセッションに時間的な制限を持たせることができます。

  • 低レイテンシ: 「インメモリ」である特性により、Redisは極めて高速です。そのため、ユーザーセッションやキャッシュデータの保存によく使われています。

  • スケーラビリティ: Redisは大量のデータと高スループットのトラフィックを処理できるように設計されています。

さらに、ユーザーセッションデータの保存方法として最も一般的な選択肢のひとつである「クライアントサイドCookie」とRedisを比較してみましょう。クライアントサイドCookieに対するRedisの優位点は以下の通りです。

  • ユーザーによる改ざんへの耐性が高い: Cookieはユーザーから見えており、改変可能です。Redisなら、ユーザーデータをユーザーによる操作から保護できます。

  • クライアントとサーバー間の転送データ量が少ない: すべてのセッション情報をRedisに保存するため、クライアントマシン側には何も保存する必要がありません。

  • クライアント側には「セッションID」だけを保存: Redisを使えば、各リクエストがどのセッションに属するのかを判断するために必要なのは、セッションIDだけです。

Upstash Redisデータベースの作成

Upstash Redisのセットアップに入る前に、まずUpstash Redisを使うメリットを理解しておきましょう。なぜそのツールを使うべきなのかを理解せずに使っても意味がありませんよね。

Upstash Redisを使う主なメリットは次の通りです。

  • サーバーレス: Upstash Redisはサーバーレスデータベースです。インフラのメンテナンスも、データベースのスケーリングや低レベルな設定を気にかける必要もありません。データベースを作成して使い始めるだけです。

  • グローバルなデータ分散: Upstashでは、ユーザーに近いリージョンにRedisインスタンスをデプロイでき、レイテンシをさらに削減できます。グローバルに分散したアプリケーションにとって特に有益で、ユーザーの所在地に関係なく、高速で応答性の高いセッションストレージを実現します。

  • 従量課金制: 初期費用は不要で、使用した分だけ支払う仕組みです。料金の詳細は公式サイトで確認できます。

さて、なぜUpstash Redisをセッション管理に使うのかについて疑問がなくなったところで、実際にUpstash Redisデータベースを作成していきましょう。

ここではUpstashコンソールからRedisデータベースを作成します。

「Create Database」ボタンをクリックしてRedisデータベースを作成しましょう。このチュートリアルを通じて、Upstash Redisデータベースの作成がいかに簡単で素早くできるかを再確認できます。

表示されるモーダルでは、データベースの名前を入力し、リージョンを選択します。利用しているサービスと同じリージョンを選択すると良いでしょう。

「next」ボタンをクリックしたら、料金プランを選択します。予算上限を設定できる従量課金プランがおすすめです!

これでRedisデータベースの準備が整いました。Redisダッシュボードでは、データベースのエンドポイント、接続用パスワード、ポート番号を確認できます。これらの情報は、Webアプリケーションからデータベースに接続する際に必要になります。

Next.jsとUpstash Redisで実現する安全なセッション管理の完全ガイド

以上で完了です!

Next.jsアプリでのUpstash Redisの活用

それでは、Webアプリケーションのアーキテクチャの中でRedisがどのように動作するのかを見てみましょう。

  • まず、sessionIdを持たないリクエストをクライアントブラウザから受け取ります。

  • リクエストにsessionIdが存在しないため、新しいsessionIdを生成し、Redisにハッシュを作成します。

  • sessionIdをCookieとしてレスポンスに含め、クライアントマシンに返します。

  • sessionId付きの新しいHTTPリクエストを受け取ったら、Redisから必要なセッションデータを取得し、クライアントへのレスポンスに使用します。

処理の流れをより分かりやすく可視化するため、サービスとRedisの接続を示すシーケンス図は以下の通りです。

Next.jsとUpstash Redisで実現する安全なセッション管理の完全ガイド

準備ができたら、まだNext.jsアプリをお持ちでない場合は、ターミナルで以下のコマンドを実行して新規作成しましょう。

npx create-next-app@latest <project-name>

次に、Upstash RedisのTypeScript SDKをインストールします。

cd <project-name>
npm install @upstash/redis

必要な依存関係のインストールが完了したら、ユーザーのブラウザCookie内のセッションIDを管理し、アプリのセッションストレージであるUpstash Redisとやり取りするためのインターフェースを作成できます。

このインターフェースは/app/lib/sessionManager.tsxファイルに実装します。

import { Redis } from '@upstash/redis'
import { cookies } from 'next/headers'
 
export const redis = new Redis({
 url: '<UPSTASH-REDIS-URL>',
 token: 'UPSTASH-REDIS-TOKEN',
})
 
type SessionId = string;
type Key = 'userName' | 'sessionStatus'; // セッションデータの他のキーも追加可能
 
export async function getSessionId(): SessionId | undefined {
 const cookieStore = await cookies();
 return cookieStore.get("session-id")?.value;
}
 
async function setSessionId(sessionId: SessionId): void {
 const cookieStore = await cookies();
 cookieStore.set("session-id", sessionId);
}
 
export async function getSessionIdAndCreateIfMissing() {
 const sessionId = await getSessionId();
 if (!sessionId) {
 const newSessionId = crypto.randomUUID();
 await setSessionId(newSessionId);
 
 return newSessionId;
 }
 
 return sessionId;
}
 
export async function get(key: Key, username: string = "") {
 const sessionId = await getSessionId();
 if (!sessionId) {
 return null;
 }
 return await redis.hget(`session-${username}-${sessionId}`, key);
}
 
export async function getAll(username: string = "") {
 const sessionId = await getSessionId();
 if (!sessionId) {
 return null;
 }
 return await redis.hgetall(`session-${username}-${sessionId}`);
}
 
export async function set(key: Key, value: string, username: string = "") {
 const sessionId = await getSessionIdAndCreateIfMissing();
 await redis.hset(`session-${username}-${sessionId}`, { [key]: value });
 return redis.expire(`session-${username}-${sessionId}`, 900);
}

それぞれの関数を詳しく見ていきましょう。

  • getSessionId: セッションIDはユーザーのブラウザのCookieに保存されます。この関数は、HTTP呼び出し内のAPIに送られたブラウザCookieからセッションIDを取得します。

  • setSessionId: この関数は、引数として渡されたセッションIDをCookieに設定します。

  • getSessionIdAndCreateIfMissing: この関数はgetSessionIdを呼び出して既存のセッションIDをCookieから取得し、ユーザーのブラウザにセッションIDが存在しない場合は、新しいランダムUUIDを新しいセッションIDとして設定します。また、新しいセッションIDをCookieに追加してブラウザに返却します。

  • getSessionData: Redisからセッションデータを取得するために呼び出す関数です。指定されたキーに対応するセッションデータをUpstash Redisから取得して返します。

  • getAllSessionData: すべてのセッションデータを取得する関数です。Upstash Redisからセッションハッシュの全キーバリューペアを取得します。

  • setSessionData: 指定されたセッションのキーバリューペアを設定する関数です。

セッションIDとUpstash Redis経由のセッションストレージを管理するユーティリティ関数が揃ったので、次はこれらの関数を利用するAPIを実装していきます。

APIはとてもシンプルです。パスからユーザー名を受け取り、リクエストを受信すると、まずCookieにセッションIDが存在するかを確認します。CookieにセッションIDがない場合は、新しいIDを生成してレスポンスのCookieにセットします。セッションIDが存在する場合は、Upstash Redisのセッションを表すハッシュ内にキーが存在するかを確認します。存在しなければ、そのハッシュにキーバリューペアを作成します。

それではコードを書いていきましょう!

APIはNext.jsのApp Routerを使用して作成します。

app/api/user/[username]/route.tsxという名前のファイルを作成してください。

 import * as sessionStore from '../../lib/session'
 
 export async function GET(request: Request,{ params }: { params: Promise<{ user: string }> }){
 const userName = (await params).user;
 const sessionId = await sessionStore.getSessionIdAndCreateIfMissing();
 const sessionStatus = await sessionStore.get('sessionStatus', userName);
 if(sessionStatus == null) {
 console.log('There is no active session.');
 await sessionStore.set('sessionStatus', 'ACTIVE', userName);
 }
 return Response.json({ userName: userName, sessionId: sessionId });
}
 

このルートファイルにより、Next.jsは<URL>:3000/api/user/<username>宛てのリクエストを、ファイル内で定義されたHTTPメソッドに解決できるようになります。

次に、実際に動作を確認してみましょう。ターミナルでプロジェクトのルートディレクトリに移動し、以下のコマンドを実行してNext.jsアプリを起動します。

npm run dev

これで、ブラウザでAPIエンドポイント https://localhost:3000/api/user/noah を開けるようになりました。アクセスすると、ユーザー名とセッションIDが返されているのが確認できるはずです。

{"userName":"noah","sessionId":"804814dc-10fc-4b0a-a4c1-321f4b54d399"}

右クリックして「検証」を選択し、「Application」タブを開けば、Cookieに設定されたsession-idを確認できます。

Next.jsとUpstash Redisで実現する安全なセッション管理の完全ガイド

また、セッションがデータベース内に作成されているかどうかをUpstash Redisでも確認できます。確認するには、Upstash Redisコンソールに戻り、Redisデータベースを開いて「Data Browser」タブを開きます。

Data Browser」タブには、以下のようにセッションデータが表示されます。

Next.jsとUpstash Redisで実現する安全なセッション管理の完全ガイド

まとめ

Upstash Redisを使ってNext.jsアプリケーションのセッションを管理することで、スケーラブルかつ効率的なソリューションが実現できます。本記事では、Next.jsアプリを作成し、セッション管理ストレージとしてUpstash Redisを統合しました。

Redisデータベースをセットアップし、Next.jsとシームレスに統合することで、従来のサーバーサイド特有の複雑さを回避しながら、セッションストレージを効果的に扱えます。このアプローチは、パフォーマンスとシンプルさを求める開発者にとって理想的な選択肢となるでしょう。

本ガイドが、皆さんのNext.jsアプリケーションにおいて、Upstash Redisを信頼性の高いセッションストアとして導入するための明確な道筋を示せたことを願っています。

  1. Next.jsアプリにフィードバックウィジェットを実装する方法(Upstash Redis連携)

    ユーザーフィードバックは、製品の改善や開発の方向性を決めるうえで非常に重要な情報源です。本記事では、ユーザーから手軽にフィードバックを収集できるウィジェットをご紹介します。これはNext.jsのAPIをバックエンドとして呼び出すReactコンポーネントで、バックエンド側のAPIは受け取ったフィードバックデータをUpstash Redisデータベースへ送信するだけのシンプルな構成になっています。送信されたデータは、Upstashコンソールの「Integrations」ページからいつでも確認・管理できます。 このコンポーネントをNext.jsのページに追加すると、画面右下にアイコンが表示されます。

  2. Redisキーの基本と管理コマンド一覧|DEL・EXPIRE・TTLなどの使い方を解説

    Redisにおけるキー(Key)は、データベースに格納された値を識別・保存・取得するための一意な識別子として機能します。キーはredis-cliから各種Redisコマンドを実行することで自由に管理でき、値の追加・削除だけでなく、有効期限の設定や名前の変更なども行えます。 本記事では、Redisのキー操作に使われる代表的なコマンドを一覧形式で解説します。日々の開発や運用でキーを扱う際のリファレンスとしてご活用ください。 基本構文 Redisのキーコマンドは、以下の形式で記述します。 redis host:port> <コマンド名> <キー名> 実行例 Redisキ