セッションガード
セッションガードは、HTTPリクエスト中にユーザーのログインと認証を行うために@adonisjs/sessionパッケージを使用します。
セッションとクッキーは長い間インターネット上で使用されており、ほとんどのアプリケーションで非常に優れた機能を提供しています。したがって、サーバーレンダリングされるアプリケーションや同じトップレベルドメインのSPAウェブクライアントでは、セッションガードの使用を推奨します。
ガードの設定
認証ガードはconfig/auth.ts
ファイル内で定義されます。このファイル内のguards
オブジェクトの下に複数のガードを設定できます。
import { defineConfig } from '@adonisjs/auth'
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
const authConfig = defineConfig({
default: 'web',
guards: {
web: sessionGuard({
useRememberMeTokens: false,
provider: sessionUserProvider({
model: () => import('#models/user'),
}),
})
},
})
export default authConfig
sessionGuard
メソッドはSessionGuardクラスのインスタンスを作成します。これは、認証中にユーザーを検索するために使用できるユーザープロバイダと、リメンバートークンの動作を設定するためのオプションの設定オブジェクトを受け入れます。
sessionUserProvider
メソッドはSessionLucidUserProviderクラスのインスタンスを作成します。これは、認証に使用するモデルへの参照を受け入れます。
ログインの実行
guard.login
メソッドを使用してユーザーをログインできます。このメソッドはUserモデルのインスタンスを受け入れ、ユーザーのログインセッションを作成します。
次の例:
-
AuthFinder mixinから
verifyCredentials
メソッドを使用して、メールアドレスとパスワードでユーザーを検索します。 -
auth.use('web')
は、config/auth.ts
ファイルで設定されたSessionGuardのインスタンスを返します。 -
次に、
guard.login(user)
メソッドを呼び出して、ユーザーのログインセッションを作成します。 -
最後に、ユーザーを
/dashboard
エンドポイントにリダイレクトします。リダイレクトエンドポイントをカスタマイズしてください。
import User from '#models/user'
import { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
async store({ request, auth, response }: HttpContext) {
/**
* ステップ1:リクエストボディから資格情報を取得します。
*/
const { email, password } = request.only(['email', 'password'])
/**
* ステップ2:資格情報を検証します。
*/
const user = await User.verifyCredentials(email, password)
/**
* ステップ3:ユーザーをログインさせます。
*/
await auth.use('web').login(user)
/**
* ステップ4:保護されたルートにリダイレクトします。
*/
response.redirect('/dashboard')
}
}
ルートの保護
auth
ミドルウェアを使用して、未認証のユーザーからルートを保護できます。このミドルウェアは、名前付きミドルウェアコレクションのstart/kernel.ts
ファイル内で登録されます。
import router from '@adonisjs/core/services/router'
export const middleware = router.named({
auth: () => import('#middleware/auth_middleware')
})
未認証のユーザーから保護したいルートにauth
ミドルウェアを適用します。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', () => {})
.use(middleware.auth())
デフォルトでは、authミドルウェアはdefault
ガード(設定ファイルで定義されている)を使用してユーザーを認証します。ただし、auth
ミドルウェアを割り当てる際にガードの配列を指定することもできます。
次の例では、authミドルウェアはweb
ガードとapi
ガードを使用してリクエストを認証しようとします。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', () => {})
.use(
middleware.auth({
guards: ['web', 'api']
})
)
認証例外の処理
認証ミドルウェアは、ユーザーが認証されていない場合にE_UNAUTHORIZED_ACCESSをスローします。この例外は、次のコンテンツネゴシエーションルールを使用して自動的に処理されます。
-
Accept=application/json
ヘッダーを持つリクエストは、message
プロパティを持つエラーの配列を受け取ります。 -
Accept=application/vnd.api+json
ヘッダーを持つリクエストは、JSON API仕様に従ったエラーの配列を受け取ります。 -
サーバーレンダリングされるアプリケーションの場合、ユーザーは
/login
ページにリダイレクトされます。リダイレクトエンドポイントは、auth
ミドルウェアクラス内で設定できます。
ログイン済みのユーザーへのアクセス
auth.user
プロパティを使用して、ログイン済みのユーザーインスタンスにアクセスできます。この値は、auth
またはsilent_auth
ミドルウェアを使用するか、auth.authenticate
またはauth.check
メソッドを手動で呼び出した場合にのみ利用できます。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', async ({ auth }) => {
await auth.user!.getAllMetrics()
})
.use(middleware.auth())
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', async ({ auth }) => {
/**
* まず、ユーザーを認証します。
*/
await auth.authenticate()
/**
* 次に、ユーザーオブジェクトにアクセスします。
*/
await auth.user!.getAllMetrics()
})
サイレント認証ミドルウェア
silent_auth
ミドルウェアはauth
ミドルウェアと似ていますが、ユーザーが認証されていない場合に例外を投げません。代わりに、リクエストは通常通り続行されます。
このミドルウェアは、ユーザーを常に認証して何らかのアクションを実行したいが、ユーザーが認証されていない場合にリクエストをブロックしたくない場合に便利です。
このミドルウェアを使用する予定がある場合は、ルーターミドルウェアのリストに登録する必要があります。
import router from '@adonisjs/core/services/router'
router.use([
// ...
() => import('#middleware/silent_auth_middleware')
])
リクエストが認証されているかどうかを確認する
auth.isAuthenticated
フラグを使用して、リクエストが認証されているかどうかを確認できます。認証されたリクエストでは、auth.user
の値は常に定義されています。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', async ({ auth }) => {
if (auth.isAuthenticated) {
await auth.user!.getAllMetrics()
}
})
.use(middleware.auth())
認証されたユーザーを取得するか失敗する
auth.user
プロパティに対してnon-null assertion operatorを使用することが好きではない場合は、auth.getUserOrFail
メソッドを使用できます。このメソッドは、ユーザーオブジェクトを返すか、E_UNAUTHORIZED_ACCESS例外をスローします。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', async ({ auth }) => {
const user = auth.getUserOrFail()
await user.getAllMetrics()
})
.use(middleware.auth())
Edgeテンプレート内でユーザーにアクセスする
InitializeAuthMiddlewareは、Edgeテンプレートとctx.auth
プロパティを共有します。したがって、現在ログインしているユーザーにはauth.user
プロパティを使用してアクセスできます。
@if(auth.isAuthenticated)
<p>こんにちは{{ auth.user.email }}さん</p>
@end
保護されていないルートでログイン済みのユーザー情報を取得したい場合は、auth.check
メソッドを使用してユーザーがログインしているかどうかを確認し、auth.user
プロパティにアクセスできます。これは、公開ページのウェブサイトヘッダーにログイン済みのユーザー情報を表示する場合に非常に便利です。
{{--
これは公開ページです。したがって、authミドルウェアによって保護されていません。
ただし、ウェブサイトのヘッダーにログイン済みのユーザー情報を表示したい場合があります。
そのために、`auth.check`メソッドを使用してユーザーがログインしているかどうかを
静かにチェックし、ヘッダーにメールアドレスを表示します。
アイデアがわかりますね!
--}}
@eval(await auth.check())
<header>
@if(auth.isAuthenticated)
<p>こんにちは{{ auth.user.email }}さん</p>
@end
</header>
ログアウトの実行
guard.logout
メソッドを使用してユーザーをログアウトできます。ログアウト時には、ユーザーの状態がセッションストアから削除されます。現在アクティブなリメンバートークンも削除されます(リメンバートークンを使用している場合)。
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.post('logout', async ({ auth, response }) => {
await auth.use('web').logout()
return response.redirect('/login')
})
.use(middleware.auth())
リメンバーミー機能の使用
リメンバーミー機能は、セッションの有効期限が切れた後に自動的にユーザーをログインさせる機能です。これは、暗号的に安全なトークンを生成し、ユーザーのブラウザにクッキーとして保存することで実現されます。
ユーザーのセッションが期限切れになった後、AdonisJSはリメンバーミークッキーを使用してトークンの有効性を検証し、自動的にユーザーのログインセッションを再作成します。
リメンバーミートークンテーブルの作成
リメンバーミートークンはデータベースに保存されるため、remember_me_tokens
テーブルを作成するために新しいマイグレーションを作成する必要があります。
node ace make:migration remember_me_tokens
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'remember_me_tokens'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments()
table
.integer('tokenable_id')
.notNullable()
.unsigned()
.references('id')
.inTable('users')
.onDelete('CASCADE')
table.string('hash').notNullable().unique()
table.timestamp('created_at').notNullable()
table.timestamp('updated_at').notNullable()
table.timestamp('expires_at').notNullable()
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
トークンプロバイダの設定
トークンの読み書きには、DbRememberMeTokensProviderをUserモデルに割り当てる必要があります。
import { BaseModel } from '@adonisjs/lucid/orm'
import { DbRememberMeTokensProvider } from '@adonisjs/auth/session'
export default class User extends BaseModel {
// ...モデルの残りのプロパティ
static rememberMeTokens = DbRememberMeTokensProvider.forModel(User)
}
設定ファイルでリメンバーミートークンを有効にする
最後に、config/auth.ts
ファイル内のセッションガード設定でuseRememberTokens
フラグを有効にします。
import { defineConfig } from '@adonisjs/auth'
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
const authConfig = defineConfig({
default: 'web',
guards: {
web: sessionGuard({
useRememberMeTokens: true,
rememberMeTokensAge: '2 years',
provider: sessionUserProvider({
model: () => import('#models/user'),
}),
})
},
})
export default authConfig
ログイン時にユーザーを記憶する
セットアップが完了したら、次のようにguard.login
メソッドを使用して、リメンバーミートークンとクッキーを生成できます。
import User from '#models/user'
import { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
async store({ request, auth, response }: HttpContext) {
const { email, password } = request.only(['email', 'password'])
const user = await User.verifyCredentials(email, password)
await auth.use('web').login(
user,
/**
* "remember_me"の入力が存在する場合にトークンを生成します
*/
!!request.input('remember_me')
)
response.redirect('/dashboard')
}
}
guestミドルウェアの使用
authパッケージには、ログインしているユーザーが/login
ページにアクセスできないようにリダイレクトするために使用できるguestミドルウェアが付属しています。これは、1つのデバイス上の1人のユーザーに対して複数のセッションを作成するのを避けるために行う必要があります。
import router from '@adonisjs/core/services/router'
import { middleware } from '#start/kernel'
router
.get('/login', () => {})
.use(middleware.guest())
デフォルトでは、guestミドルウェアはdefault
ガード(設定ファイルで定義されている)を使用してユーザーのログイン状態をチェックします。ただし、guest
ミドルウェアを割り当てる際にガードの配列を指定することもできます。
router
.get('/login', () => {})
.use(middleware.guest({
guards: ['web', 'admin_web']
}))
最後に、ログインしているユーザーのリダイレクトルートを./app/middleware/guest_middleware.ts
ファイル内で設定できます。
イベント
利用可能なイベントのリストを表示するには、イベントリファレンスガイドを参照してください。