セッション
必須依存関係: io.ktor:ktor-server-sessions
コード例: session-cookie-client, session-cookie-server, session-header-server
[Sessions](https://api.ktor.io/ktor-server/ktor-server-plugins/ktor-server-sessions/io.ktor.server.sessions/-sessions.html)
プラグインは、異なるHTTPリクエスト間でデータを永続化するメカニズムを提供します。一般的な使用例としては、ログイン中のユーザーIDの保存、ショッピングカートの内容、またはクライアント上でのユーザー設定の保持などがあります。Ktorでは、Cookieまたはカスタムヘッダーを使用してセッションを実装し、セッションデータをサーバーに保存するかクライアントに渡すかを選択したり、セッションデータを署名・暗号化したりすることができます。
このトピックでは、Sessions
プラグインのインストール方法、構成方法、およびルートハンドラー内でのセッションデータへのアクセス方法について説明します。
依存関係の追加
セッションのサポートを有効にするには、ビルドスクリプトにktor-server-sessions
アーティファクトを含める必要があります。
セッションのインストール
アプリケーションにSessions
プラグインをインストールするには、 指定された
install
関数に渡します。 以下のコードスニペットは、Sessions
をインストールする方法を示しています... - ...
embeddedServer
関数呼び出し内。 - ...
Application
クラスの拡張関数である、明示的に定義されたmodule
内。
Sessions
プラグインは、特定のルートにもインストールできます。 これは、異なるアプリケーションリソースに対して異なるSessions
設定が必要な場合に役立つことがあります。
セッション設定の概要
Sessions
プラグインを設定するには、以下の手順を実行する必要があります。
サーバーとクライアント間でデータを渡す方法を選択: Cookieまたはカスタムヘッダーを使用します。CookieはプレーンなHTMLアプリケーションに適しており、カスタムヘッダーはAPI向けです。
セッションペイロードの保存場所を選択: クライアントまたはサーバー。シリアライズされたセッションデータをCookie/ヘッダー値を使用してクライアントに渡すか、ペイロードをサーバーに保存しセッション識別子のみを渡すことができます。
セッションペイロードをサーバーに保存したい場合は、*保存方法*を選択できます。サーバーのメモリ内、またはフォルダ内です。セッションデータを保持するためのカスタムストレージを実装することもできます。
セッションデータの保護: クライアントに渡される機密性の高いセッションデータを保護するために、セッションのペイロードを署名および暗号化する必要があります。
Sessions
の設定後、ルートハンドラー内でセッションデータを取得および設定できます。
データクラスの作成
セッションを設定する前に、セッションデータを保存するためのデータクラスを作成する必要があります。 たとえば、以下のUserSession
クラスはセッションIDとページビュー数を保存するために使用されます。
@Serializable
data class UserSession(val id: String, val count: Int)
複数のセッションを使用する場合は、複数のデータクラスを作成する必要があります。
セッションデータの受け渡し: Cookie vs ヘッダー
Cookie
Cookieを使用してセッションデータを渡すには、install(Sessions)
ブロック内で、指定された名前とデータクラスを持つcookie
関数を呼び出します。
install(Sessions) {
cookie<UserSession>("user_session")
}
上記の例では、セッションデータはSet-Cookie
ヘッダーに追加されたuser_session
属性を使用してクライアントに渡されます。cookie
ブロック内で他のCookie属性を渡すことで、それらを構成できます。たとえば、以下のコードスニペットは、Cookieのパスと有効期限を指定する方法を示しています。
install(Sessions) {
cookie<UserSession>("user_session") {
cookie.path = "/"
cookie.maxAgeInSeconds = 10
}
}
必要な属性が明示的に公開されていない場合は、extensions
プロパティを使用します。たとえば、SameSite
属性は次のように渡すことができます。
install(Sessions) {
cookie<UserSession>("user_session") {
cookie.extensions["SameSite"] = "lax"
}
}
利用可能な設定の詳細については、CookieConfigurationを参照してください。
アプリケーションを本番環境にデプロイする前に、
secure
プロパティがtrue
に設定されていることを確認してください。 これにより、安全な接続を介したCookieの転送のみが有効になり、HTTPSダウングレード攻撃からセッションデータを保護します。
ヘッダー
カスタムヘッダーを使用してセッションデータを渡すには、install(Sessions)
ブロック内で、指定された名前とデータクラスを持つheader
関数を呼び出します。
install(Sessions) {
header<CartSession>("cart_session")
}
上記の例では、セッションデータはcart_session
カスタムヘッダーを使用してクライアントに渡されます。 クライアント側では、セッションデータを取得するために各リクエストにこのヘッダーを追加する必要があります。
クロスオリジンリクエストを処理するためにCORSプラグインを使用している場合は、以下のようにカスタムヘッダーを
CORS
設定に追加します。kotlininstall(CORS) { allowHeader("cart_session") exposeHeader("cart_session") }
セッションペイロードの保存: クライアント vs サーバー
Ktorでは、セッションデータを2つの方法で管理できます。
クライアントとサーバー間でセッションデータを渡す。
cookieまたはheader関数にセッション名のみを渡す場合、セッションデータはクライアントとサーバー間で渡されます。この場合、クライアントに渡される機密性の高いセッションデータを保護するために、セッションのペイロードを署名および暗号化する必要があります。
セッションデータをサーバーに保存し、セッションIDのみをクライアントとサーバー間で渡す。
そのような場合、サーバー上でペイロードをどこに保存するかを選択できます。たとえば、セッションデータをメモリ内、指定されたフォルダ内、または独自のカスタムストレージを実装して保存できます。
サーバーへのセッションペイロードの保存
Ktorでは、セッションデータをサーバーに保存し、セッションIDのみをサーバーとクライアント間で渡すことができます。この場合、サーバー上でペイロードをどこに保持するかを選択できます。
インメモリストレージ
SessionStorageMemoryを使用すると、セッションの内容をメモリに保存できます。このストレージは、サーバーの実行中にデータを保持し、サーバーが停止すると情報を破棄します。たとえば、次のようにCookieをサーバーメモリに保存できます。
cookie<CartSession>("cart_session", SessionStorageMemory()) {
}
完全な例はこちらで確認できます: session-cookie-server。
SessionStorageMemory
は開発目的のみを意図しています。
ディレクトリストレージ
directorySessionStorageは、指定されたディレクトリ内のファイルにセッションデータを保存するために使用できます。たとえば、build/.sessions
ディレクトリ内のファイルにセッションデータを保存するには、次のようにdirectorySessionStorage
を作成します。
header<CartSession>("cart_session", directorySessionStorage(File("build/.sessions"))) {
}
完全な例はこちらで確認できます: session-header-server。
カスタムストレージ
Ktorは、カスタムストレージを実装できるSessionStorageインターフェースを提供します。
interface SessionStorage {
suspend fun invalidate(id: String)
suspend fun write(id: String, value: String)
suspend fun read(id: String): String
}
3つの関数はすべてサスペンド関数です。SessionStorageMemoryを参考にすることができます。
セッションデータの保護
セッションデータの署名
セッションデータに署名することで、セッションの内容が改変されるのを防ぎますが、ユーザーはこの内容を見ることができます。 セッションに署名するには、SessionTransportTransformerMessageAuthentication
コンストラクタに署名キーを渡し、このインスタンスをtransform
関数に渡します。
install(Sessions) {
val secretSignKey = hex("6819b57a326945c1968f45236589")
cookie<CartSession>("cart_session", SessionStorageMemory()) {
cookie.path = "/"
transform(SessionTransportTransformerMessageAuthentication(secretSignKey))
}
}
SessionTransportTransformerMessageAuthentication
はデフォルトの認証アルゴリズムとしてHmacSHA256
を使用しますが、これは変更可能です。
セッションデータの署名と暗号化
セッションデータを署名および暗号化することで、セッションの内容が読み取られたり、改変されたりするのを防ぎます。 セッションを署名および暗号化するには、SessionTransportTransformerEncrypt
コンストラクタに署名/暗号化キーを渡し、このインスタンスをtransform
関数に渡します。
install(Sessions) {
val secretEncryptKey = hex("00112233445566778899aabbccddeeff")
val secretSignKey = hex("6819b57a326945c1968f45236589")
cookie<UserSession>("user_session") {
cookie.path = "/"
cookie.maxAgeInSeconds = 10
transform(SessionTransportTransformerEncrypt(secretEncryptKey, secretSignKey))
}
}
Ktorバージョン
3.0.0
で暗号化メソッドが更新されたことに注意してください。 以前のバージョンから移行する場合は、既存のセッションとの互換性を確保するために、SessionTransportTransformerEncrypt
のコンストラクタでbackwardCompatibleRead
プロパティを使用してください。
デフォルトでは、SessionTransportTransformerEncrypt
はAES
とHmacSHA256
アルゴリズムを使用しますが、これらは変更可能です。
署名/暗号化キーはコードで指定すべきではありません。 署名/暗号化キーを保存し、環境変数を使用してそれらを初期化するために、設定ファイルでカスタムグループを使用できます。
セッションコンテンツの取得と設定
特定のルートのセッションコンテンツを設定するには、call.sessions
プロパティを使用します。set
メソッドを使用すると、新しいセッションインスタンスを作成できます。
get("/login") {
call.sessions.set(UserSession(id = "123abc", count = 0))
call.respondRedirect("/user")
}
セッションコンテンツを取得するには、登録済みのセッション型のいずれかを型パラメータとして受け取るget
を呼び出すことができます。
get("/user") {
val userSession = call.sessions.get<UserSession>()
if (userSession != null) {
}
たとえば、カウンターをインクリメントするためにセッションを変更するには、データクラスのcopy
メソッドを呼び出す必要があります。
get("/user") {
val userSession = call.sessions.get<UserSession>()
if (userSession != null) {
call.sessions.set(userSession.copy(count = userSession.count + 1))
call.respondText("Session ID is ${userSession.id}. Reload count is ${userSession.count}.")
} else {
call.respondText("Session doesn't exist or is expired.")
}
}
何らかの理由でセッションをクリアする必要がある場合(たとえば、ユーザーがログアウトした場合)、clear
関数を呼び出します。
get("/logout") {
call.sessions.clear<UserSession>()
call.respondRedirect("/user")
}
完全な例はこちらで確認できます: session-cookie-client。
遅延セッション取得
デフォルトでは、Ktorはセッションを含むすべてのリクエストに対して、ルートが実際に必要としているかどうかにかかわらず、ストレージからセッションを読み取ろうとします。この動作は、特にカスタムセッションストレージを使用するアプリケーションにおいて、不要なオーバーヘッドを引き起こす可能性があります。
io.ktor.server.sessions.deferred
システムプロパティを有効にすることで、セッションの読み込みを遅延させることができます。
System.setProperty("io.ktor.server.sessions.deferred", "true")
例
以下の実行可能な例は、Sessions
プラグインの使用方法を示しています。
- session-cookie-clientは、署名および暗号化されたセッションペイロードをCookieを使用してクライアントに渡す方法を示します。
- session-cookie-serverは、セッションペイロードをサーバーメモリに保持し、署名されたセッションIDをCookieを使用してクライアントに渡す方法を示します。
- session-header-serverは、セッションペイロードをサーバー上のディレクトリストレージに保持し、署名されたセッションIDをカスタムヘッダーを使用してクライアントに渡す方法を示します。