セッション

セッション

@adonisjs/sessionパッケージを使用して、AdonisJSアプリケーション内でユーザーセッションを管理できます。セッションパッケージは、さまざまなストレージプロバイダー間でセッションデータを保存するための統一されたAPIを提供します。

以下はバンドルされたストアのリストです。

  • cookie: セッションデータは暗号化されたクッキー内に保存されます。クッキーストアは、データがクライアント側に保存されるため、マルチサーバーデプロイメントで優れたパフォーマンスを発揮します。

  • file: セッションデータはサーバー内のファイルに保存されます。ファイルストアは、ロードバランサーとスティッキーセッションを実装する場合にのみ、マルチサーバーデプロイメントにスケールアウトします。

  • redis: セッションデータはRedisデータベース内に保存されます。Redisストアは、大量のセッションデータを持つアプリケーションに推奨され、マルチサーバーデプロイメントにスケールアウトできます。

  • memory: セッションデータはグローバルメモリストア内に保存されます。メモリストアはテスト中に使用されます。

組み込みのバックエンドストアに加えて、カスタムセッションストアを作成して登録することもできます。

インストール

次のコマンドを使用してパッケージをインストールし、設定します:

node ace add @adonisjs/session
  1. 検出されたパッケージマネージャーを使用して@adonisjs/sessionパッケージをインストールします。

  2. adonisrc.tsファイル内に次のサービスプロバイダーを登録します。

    {
    providers: [
    // ...other providers
    () => import('@adonisjs/session/session_provider')
    ]
    }
  3. config/session.tsファイルを作成します。

  4. 次の環境変数とそのバリデーションを定義します。

    SESSION_DRIVER=cookie
  5. start/kernel.tsファイル内に次のミドルウェアを登録します。

    router.use([
    () => import('@adonisjs/session/session_middleware')
    ])

設定

セッションパッケージの設定は、config/session.tsファイルに保存されます。

参照: セッション設定スタブ

import env from '#start/env'
import app from '@adonisjs/core/services/app'
import { defineConfig, stores } from '@adonisjs/session'
export default defineConfig({
age: '2h',
enabled: true,
cookieName: 'adonis-session',
clearWithBrowser: false,
cookie: {
path: '/',
httpOnly: true,
secure: app.inProduction,
sameSite: 'lax',
},
store: env.get('SESSION_DRIVER'),
stores: {
cookie: stores.cookie(),
}
})

enabled

ミドルウェアを一時的に有効または無効にします。ミドルウェアスタックから削除することなく、一時的に無効にできます。

cookieName

セッションIDを保存するためのクッキー名です。必要に応じて名前を変更してください。

clearWithBrowser

trueに設定すると、ユーザーがブラウザウィンドウを閉じた後にセッションIDクッキーが削除されます。このクッキーは、技術的にはセッションクッキーとして知られています。

age

ageプロパティは、ユーザーアクティビティなしでセッションデータの有効性を制御します。指定された期間が経過すると、セッションデータは期限切れと見なされます。

cookie

セッションIDクッキーの属性を制御します。cookieの設定も参照してください。

store

セッションデータを保存するために使用するストアを定義します。固定値または環境変数から読み取ることができます。

stores

storesオブジェクトは、1つまたは複数のバックエンドストアを設定するために使用されます。

ほとんどのアプリケーションでは、単一のストアを使用します。ただし、複数のストアを設定し、アプリケーションが実行される環境に基づいて切り替えることもできます。


ストアの設定

@adonisjs/sessionパッケージにバンドルされたバックエンドストアのリストは次のとおりです。

import app from '@adonisjs/core/services/app'
import { defineConfig, stores } from '@adonisjs/session'
export default defineConfig({
store: env.get('SESSION_DRIVER'),
stores: {
cookie: stores.cookie(),
file: stores.file({
location: app.tmpPath('sessions')
}),
redis: stores.redis({
connection: 'main'
})
}
})

stores.cookie

cookieストアは、セッションデータを暗号化してクッキー内に保存します。

stores.file

fileストアの設定を定義します。このメソッドは、セッションファイルの保存場所としてlocationパスを受け入れます。

stores.redis

redisストアの設定を定義します。このメソッドは、セッションデータの保存に使用するconnection名を受け入れます。

redisストアを使用する前に、@adonisjs/redisパッケージをインストールして設定する必要があります。


環境変数のバリデーションの更新

デフォルト以外のセッションストアを使用する場合は、SESSION_DRIVER環境変数のバリデーションも更新する必要があります。

次の例では、cookieストアとredisストアを設定しています。したがって、SESSION_DRIVER環境変数もこれらのいずれかになるように許可する必要があります。

import { defineConfig, stores } from '@adonisjs/session'
export default defineConfig({
store: env.get('SESSION_DRIVER'),
stores: {
cookie: stores.cookie(),
redis: stores.redis({
connection: 'main'
})
}
})
start/env.ts
{
SESSION_DRIVER: Env.schema.enum(['cookie', 'redis', 'memory'] as const)
}

基本的な例

セッションパッケージが登録されたら、HTTPコンテキストからsessionプロパティにアクセスできます。sessionプロパティは、セッションストアへのデータの読み書きに使用するAPIを公開します。

import router from '@adonisjs/core/services/router'
router.get('/theme/:color', async ({ params, session, response }) => {
session.put('theme', params.color)
response.redirect('/')
})
router.get('/', async ({ session }) => {
const colorTheme = session.get('theme')
return `You are using ${colorTheme} color theme`
})

セッションデータはリクエストの開始時にセッションストアから読み取られ、リクエストの終了時にストアに書き戻されます。そのため、すべての変更はリクエストが完了するまでメモリに保持されます。

サポートされるデータ型

セッションデータはJSON.stringifyを使用して文字列にシリアライズされるため、次のJavaScriptのデータ型をセッションの値として使用できます。

  • 文字列
  • 数値
  • bigInt
  • ブール値
  • null
  • オブジェクト
  • 配列
// オブジェクト
session.put('user', {
id: 1,
fullName: 'virk',
})
// 配列
session.put('product_ids', [1, 2, 3, 4])
// ブール値
session.put('is_logged_in', true)
// 数値
session.put('visits', 10)
// bigInt
session.put('visits', BigInt(10))
// 日付オブジェクトはISO文字列に変換されます
session.put('visited_at', new Date())

データの読み書き

sessionオブジェクトからデータとのやり取りするためのメソッドのリストは次のとおりです。

get

ストアからキーの値を返します。ネストされた値を読み取るためにドット記法を使用できます。

session.get('key')
session.get('user.email')

2番目のパラメータとしてデフォルト値を定義することもできます。キーがストアに存在しない場合、デフォルト値が返されます。

session.get('visits', 0)

has

セッションストアにキーが存在するかどうかを確認します。

if (session.has('visits')) {
}

all

セッションストアからすべてのデータを返します。返される値は常にオブジェクトです。

session.all()

put

キーと値のペアをセッションストアに追加します。ドット記法を使用してネストされた値を持つオブジェクトを作成できます。

session.put('user', { email: 'foo@bar.com' })
// 上記と同じ
session.put('user.email', 'foo@bar.com')

forget

セッションストアからキーと値のペアを削除します。

session.forget('user')
// ユーザーオブジェクトからemailを削除します
session.forget('user.email')

pull

pullメソッドはキーの値を返し、同時にストアから削除します。

const user = session.pull('user')
session.has('user') // false

increment

incrementメソッドはキーの値を増やします。キーが存在しない場合は新しいキー値が定義されます。

session.increment('visits')
// 4増やす
session.increment('visits', 4)

decrement

decrementメソッドはキーの値を減らします。キーが存在しない場合は新しいキー値が定義されます。

session.decrement('visits')
// 4減らす
session.decrement('visits', 4)

clear

clearメソッドはセッションストアからすべてのデータを削除します。

session.clear()

セッションのライフサイクル

AdonisJSは最初のHTTPリクエスト時に空のセッションストアを作成し、一意のセッションIDに割り当てます。セッションリクエスト/レスポンスのライフサイクルがセッションに関与しない場合でも、maxAgeプロパティを更新してセッションIDクッキーが期限切れにならないようにします。また、セッションストアに変更がある場合は、変更を更新および永続化するために通知されます。

次のリクエストごとに、セッションIDクッキーのmaxAgeプロパティを更新して、期限切れにならないようにします。また、セッションストアには変更がある場合には通知され、変更が更新されて永続化されます。

sessionIdプロパティを使用して一意のセッションIDにアクセスできます。訪問者のセッションIDは期限切れになるまで変わりません。

console.log(session.sessionId)

セッションIDの再生成

セッションIDを再生成することで、アプリケーション内のセッション固定攻撃を防ぐことができます。匿名セッションをログイン済みユーザーに関連付ける場合は、セッションIDを再生成する必要があります。

@adonisjs/authパッケージはセッションIDを自動的に再生成するため、手動で行う必要はありません。

/**
* リクエストの最後に新しいセッションIDが割り当てられます
*/
session.regenerate()

フラッシュメッセージ

フラッシュメッセージは、2つのHTTPリクエスト間でデータを渡すために使用されます。特定のアクションの後にユーザーにフィードバックを提供するためによく使用されます。たとえば、フォームの送信後に成功メッセージを表示したり、バリデーションエラーメッセージを表示したりします。

以下の例では、連絡フォームの表示とフォームの詳細をデータベースに送信するためのルートを定義しています。フォームの送信後、フラッシュメッセージを使用してユーザーをフォームに戻し、成功通知を表示します。

import router from '@adonisjs/core/services/router'
router.post('/contact', ({ session, request, response }) => {
const data = request.all()
// 連絡先データを保存
session.flash('notification', {
type: 'success',
message: 'お問い合わせいただきありがとうございます。後ほどご連絡いたします。'
})
response.redirect().back()
})
router.get('/contact', ({ view }) => {
return view.render('contact')
})

Edgeテンプレート内でフラッシュメッセージにアクセスするには、flashMessageタグまたはflashMessagesプロパティを使用できます。

@flashMessage('notification')
<div class="notification {{ $message.type }}">
{{ $message.message }}
</div>
@end
<form method="POST" action="/contact">
<!-- フォームの残りの部分 -->
</form>

コントローラ内でフラッシュメッセージにアクセスするには、session.flashMessagesプロパティを使用できます。

router.get('/contact', ({ view, session }) => {
console.log(session.flashMessages.all())
return view.render('contact')
})

バリデーションエラーとフラッシュメッセージ

セッションミドルウェアは自動的にバリデーション例外をキャプチャし、ユーザーをフォームにリダイレクトします。バリデーションエラーとフォームの入力データはフラッシュメッセージ内に保持され、Edgeテンプレート内でアクセスできます。

次の例では、以下のことを行っています。

  • title入力フィールドの値にはoldメソッドを使用してアクセスします。
  • エラーメッセージには@inputErrorタグを使用してアクセスします。
<form method="POST" action="/posts">
<div>
<label for="title"> タイトル </label>
<input
type="text"
id="title"
name="title"
value="{{ old('title') || '' }}"
/>
@inputError('title')
@each(message in $messages)
<p> {{ message }} </p>
@end
@end
</div>
</form>

フラッシュメッセージの書き込み

フラッシュメッセージストアにデータを書き込むためのメソッドは次のとおりです。session.flashメソッドはキーと値のペアを受け取り、それをセッションストア内のフラッシュメッセージプロパティに書き込みます。

session.flash('key', value)
session.flash({
key: value
})

リクエストデータを手動で読み取り、フラッシュメッセージに保存する代わりに、次のいずれかのメソッドを使用してフォームデータをフラッシュできます。

flashAll
/**
* リクエストデータをフラッシュするためのショートハンド
*/
session.flashAll()
/**
* "flashAll"と同じ
*/
session.flash(request.all())
flashOnly
/**
* リクエストデータから選択したプロパティをフラッシュするためのショートハンド
*/
session.flashOnly(['username', 'email'])
/**
* "flashOnly"と同じ
*/
session.flash(request.only(['username', 'email']))
flashExcept
/**
* リクエストデータから選択したプロパティをフラッシュするためのショートハンド
*/
session.flashExcept(['password'])
/**
* "flashExcept"と同じ
*/
session.flash(request.except(['password']))

最後に、現在のフラッシュメッセージを再度フラッシュする場合は、session.reflashメソッドを使用できます。

session.reflash()
session.reflashOnly(['notification', 'errors'])
session.reflashExcept(['errors'])

フラッシュメッセージの読み取り

フラッシュメッセージはリダイレクト後の次のリクエストでのみ利用可能です。これらにはsession.flashMessagesプロパティを使用してアクセスできます。

console.log(session.flashMessages.all())
console.log(session.flashMessages.get('key'))
console.log(session.flashMessages.has('key'))

同じflashMessagesプロパティはEdgeテンプレートでも共有されており、次のようにアクセスできます。

参照: Edgeヘルパーリファレンス

{{ flashMessages.all() }}
{{ flashMessages.get('key') }}
{{ flashMessages.has('key') }}

最後に、次のEdgeタグを使用して特定のフラッシュメッセージまたはバリデーションエラーにアクセスできます。

{{-- キーによって任意のフラッシュメッセージを読み取る --}}
@flashMessage('key')
{{ inspect($message) }}
@end
{{-- 一般的なエラーを読み取る --}}
@error('key')
{{ inspect($message) }}
@end
{{-- バリデーションエラーを読み取る --}}
@inputError('key')
{{ inspect($messages) }}
@end

イベント

@adonisjs/sessionパッケージがディスパッチするイベントのリストは、イベントリファレンスガイドを参照してください。

カスタムセッションストアの作成

セッションストアは、SessionStoreContractインターフェイスを実装し、次のメソッドを定義する必要があります。

import {
SessionData,
SessionStoreFactory,
SessionStoreContract,
} from '@adonisjs/session/types'
/**
* 受け入れる設定
*/
export type MongoDBConfig = {}
/**
* ドライバの実装
*/
export class MongoDBStore implements SessionStoreContract {
constructor(public config: MongoDBConfig) {
}
/**
* セッションIDに対するセッションデータを返します。メソッドはnullまたはキーと値のペアのオブジェクトを返さなければなりません。
*/
async read(sessionId: string): Promise<SessionData | null> {
}
/**
* セッションデータを提供されたセッションIDに対して保存します。
*/
async write(sessionId: string, data: SessionData): Promise<void> {
}
/**
* 指定されたセッションIDのセッションデータを削除します。
*/
async destroy(sessionId: string): Promise<void> {
}
/**
* セッションの有効期限をリセットします。
*/
async touch(sessionId: string): Promise<void> {
}
}
/**
* ストアを参照するためのファクトリ関数
*/
export function mongoDbStore (config: MongoDbConfig): SessionStoreFactory {
return (ctx, sessionConfig) => {
return new MongoDBStore(config)
}
}

上記のコード例では、次の値をエクスポートしています。

  • MongoDBConfig: 受け入れる設定のTypeScriptの型です。

  • MongoDBStore: クラスとしてのストアの実装です。SessionStoreContractインターフェイスに準拠する必要があります。

  • mongoDbStore: 最後に、HTTPリクエストごとにストアのインスタンスを作成するためのファクトリ関数です。

ストアの使用

ストアが作成されたら、mongoDbStoreファクトリ関数を使用して設定ファイル内で参照できます。

config/session.ts
import { defineConfig } from '@adonisjs/session'
import { mongDbStore } from 'my-custom-package'
export default defineConfig({
stores: {
mongodb: mongoDbStore({
// 設定はここに記述します
})
}
})

データのシリアライズについて

writeメソッドはセッションデータをオブジェクトとして受け取り、保存する前に文字列に変換する必要がある場合があります。これには任意のシリアライズパッケージを使用するか、AdonisJSヘルパーモジュールが提供するMessageBuilderヘルパーを使用できます。インスピレーションのために、公式のセッションストアを参照してください。