ログインの実装 (Svelte & Lucia)

このコードは、SvelteKitのサーバーサイド機能を活用して、ユーザーログインの処理を行うものです。Luciaを使用してセッション管理を行い、認証の流れを実装しています。

+page.server.ts: ログイン処理とリダイレクト

load 関数: セッションの検証とリダイレクト

import type { Actions } from "@sveltejs/kit";
import { auth } from "$lib/server/lucia";
import { fail, redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";

export const load = (async ({ locals }) => {
  const session = await locals.auth.validate();

  if (!session) {
    return {};
  }

  redirect(303, "/");
}) satisfies PageServerLoad;

解説

  1. locals.auth.validate() を使い、現在のセッションが有効かを確認。
  2. セッションがない場合 {} を返してログインページを表示。
  3. セッションが有効なら redirect(303, "/") でトップページへ遷移。
  4. satisfies PageServerLoad; を使用し、型の安全性を確保。

actions オブジェクト: ログイン処理

export const actions = {
  login: async ({ request, locals }) => {
    const { username, password } = Object.fromEntries(
      await request.formData()
    ) as {
      username: string;
      password: string;
    };

    try {
      const key = await auth.useKey("username", username, password);
      const session = await auth.createSession({
        userId: key.userId,
        attributes: {},
      });
      console.log(session);
      locals.auth.setSession(session);
    } catch (error) {
      console.error(error);
      return fail(400, { message: "The username or password is incorrect." });
    }

    redirect(303, "/");
  },
} satisfies Actions;

解説

  1. request.formData() から usernamepassword を取得。
  2. auth.useKey("username", username, password) でユーザー認証を実行。
  3. 認証成功時:
    • auth.createSession() でセッションを作成。
    • locals.auth.setSession(session) でセッションを設定。
    • redirect(303, "/") でトップページへ遷移。
  4. 認証失敗時:
    • fail(400, { message: "The username or password is incorrect." }) を返し、エラーメッセージを表示。

+page.svelte: ログインフォームとエラーメッセージの表示

<script lang="ts">
  import { enhance } from "$app/forms";
  import type { ActionData } from "./$types";

  export let form: ActionData;
</script>

解説

  • enhance$app/forms からインポートし、フォーム送信を最適化。
  • form はサーバーから返される ActionData 型のエラーメッセージを格納。
<form
  class="bg-white shadow-md rounded-lg max-w-sm mx-auto mt-20 p-6"
  use:enhance
  action="?/login"
  method="post"
>
  • use:enhance でフォーム送信を最適化。
  • action="?/login"actions.login にフォームを送信。
  • method="post" でPOSTリクエストを送信。
<input type="text" id="username" name="username" required />
<input type="password" id="password" name="password" required />
  • usernamepassword の入力フィールドを作成。
  • required 属性で入力必須。
{#if form?.message}
  <div class="mt-4 p-3 bg-red-100 text-red-700 rounded-lg">{form.message}</div>
{/if}
  • form?.message がエラー時に表示される。
<p>Don't have an account? <a href="/signup">Register here.</a></p>
  • まだアカウントを持っていないユーザー向けの登録リンク。

まとめ

  • load 関数でセッションを確認し、ログイン済みならリダイレクト。
  • actions.login でユーザー認証を処理し、エラー時には適切なメッセージを表示。
  • ページ側のフォームでは use:enhance を活用し、動的なエラーメッセージを表示。
  • redirect(303, "/") でログイン成功後にトップページへ遷移。