ホーム > Laravel > Nuxt3とLaravelSanctumでCookie認証する方法
Laravel

Nuxt3とLaravelSanctumでCookie認証する方法

いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。

Nuxt3とLaravelSanctumでCookie認証する方法についてまとめました。

この記事では、全て書くと逆にわかりづらくなると思っているため

  1. ログイン認証のみ
  2. 今回設定したところにフォーカス
  3. Nuxt Sanctum Auth というパッケージを利用する

しています。

検証した環境

Laravel10
Nuxt3

Laravel 側の設定

DB の接続等については各自でお願いします。

LaravelSanctum を使えるようにする

Laravel プロジェクトでコマンド

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

これで config/sanctum.php が作成されれば OK です。ちなみに laravel10 では不要みたいです。

そしてこの config ファイル一切変更しません。

Kernel でミドルウェアを追加する

今回使用するルーティングは api.php に書いていくため、ミドルウェアを追加します。

App/Http/Kernel.php の api の項目を以下のようにします。

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Session\Middleware\StartSession::class,
        ],

これでクッキーやセッションが使えるようになりました。

cors の設定を少し変える

config/cors.php

'supports_credentials' => true, //falseから変更する

コマンドで設定の変更を反映させます

php artisan config:clear

ログイン用のコントローラーを作成

php artisan make:controller AuthController

作成した AuthController に、ログイン用の関数を追加。

セッションを regenerate しています。

use Auth;

public function login(Request $request) {
    $credentials = $request->validate([
        'email' => ['required', 'email'],
        'password' => ['required'],
    ]);

    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return response()->json(['message' => 'ログイン成功']);
    }
}

ルーティングの作成

routes/api.php

Route::post('/login', 'App\Http\Controllers\AuthController@login');

//あとで使います。
Route::group(['middleware' => 'auth:sanctum'], function () {
    Route::get('/user', function (Request $request) {
        $user = $request->user();
        \Log::info($user);
        return $user;
    });
    Route::post('/posts', function (Request $request) {
        $users = User::all();
        return response()->json(compact('users'),200);
     });
});

Laravel の設定は以上です。

Nuxt 側の設定をする

Nuxt Sanctum Auth をインストールする

ドキュメント

コマンドでインストールします。Nuxt プロジェクトで以下のコマンド

npm i nuxt-sanctum-auth

nuxt.config.[js,ts]を変更する

設定の解説についてはコメントアウトを読んでください。

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  ssr: false, //このパッケージは、SSR対応していないので書く
  devtools: { enabled: true },
  modules: [
    "nuxt-sanctum-auth",
    // ...
  ],
  nuxtSanctumAuth: {
    token: false, // token認証ならここをTrueにするが、今回はクッキー認証なのでfalse
    baseUrl: "http://localhost:8081", //Laravel側のローカルサーバー
    endpoints: {
      csrf: "/sanctum/csrf-cookie", //csrf-tokenをサーバーからGETするURL。Laravelの設定がデフォルトならこれ
      login: "/api/login", //ログイン用、サーバーにPOSTするURL。
      logout: "/api/logout", //ログアウト用、サーバーにPOSTするURL。今回は使わない
      user: "/api/user", //ユーザー情報をサーバーからGETするURL
    },
    csrf: {
      headerKey: "X-XSRF-TOKEN",
      cookieKey: "XSRF-TOKEN",
      tokenCookieKey: "nuxt-sanctum-auth-token", //デフォルトならこのままでOK
    },
    redirects: {
      home: "/show", //ログイン後などでリダイレクト
      login: "/login", //ログインページ
      logout: "/", //ログアウト後
    },
  },
})

表示するためのファイル

  • ルーティングを使うため

app.vue

<template>
  <div>
    <NuxtPage />
  </div>
</template>
  • ログインページ

pages/login.vue

<template>
  <div>
    <div>
      <form>
        <dl>
          <dt>メールアドレス:</dt>
          <dd><input id="email" type="string" v-model="email" /></dd>
        </dl>
        <dl>
          <dt><label for="password">パスワード:</label></dt>
          <dd><input id="password" type="password" v-model="password" /></dd>
        </dl>
        <button type="button" @click="login">ログイン</button>
      </form>
    </div>
  </div>
</template>

<script setup>
definePageMeta({
  middleware: "guest",
})
const { $sanctumAuth } = useNuxtApp()
const router = useRouter()
const login = async () => {
  await $sanctumAuth.login({
    email: "test@test.com", // テストユーザーのメールアドレス
    password: "password", // テストユーザーのパスワード
  })
}
</script>

<style scoped></style>

ログインボタン押せばログインできます。

pages というフォルダは各自作成してファイルを作成しました。

  • ログイン後のページも作成。

pages/show.vue

<script setup>
definePageMeta({
  middleware: "auth",
})

const { $apiFetch } = useNuxtApp()
const users = ref()
const { user, loggedIn } = useAuth() // or useState('auth').value

const post = async () => {
  const response = await $apiFetch(`api/posts`, { method: "POST" })
  users.value = response.users
}
</script>

<template>
  <div>
    <div v-for="user in users">{{ user.name }}</div>
    <div>
      <button @click="post">ポスト</button>
    </div>
  </div>
</template>

<style></style>

ログインページの解説

  1. ログインしていないユーザーしか見られないページ
definePageMeta({
  middleware: "guest",
})
  1. 認証にはこの $sanctumAuth を使う
const { $sanctumAuth } = useNuxtApp()
  1. ログインするための関数

この関数が動けばログインできます。

const login = async () => {
  await $sanctumAuth.login({
    email: "test@test.com", // テストユーザーのメールアドレス
    password: "password", // テストユーザーのパスワード
  })
}

email とパスワードがテストユーザーとマッチすれば、これだけでログインできます。

ログイン後どのように使うか

基本的に JS の fetch を、

このパッケージ独特の関数である$apiFetch に置き換えれば、あとは同じように GET も POST もできそうです。

show.vue に書かれているコード

const users = ref()
const { $apiFetch } = useNuxtApp()
const post = async () => {
  const response = await $apiFetch(`api/posts`, { method: "POST" })
  users.value = response.users
}

この部分です。

post という関数が動けば、

users のデータを取得する POST 送信を実装しています。

テストユーザーの作り方については、

テストユーザーの作り方

こちらを参照してください。

注意点

現時点このパッケージを使うと、SSR には対応していないようです。

ちなみに SSR で実装しようとすると、F5 等で画面を更新した挙動が変になりました。

サーバーでログイン・非ログインを判定
→ 非ログインと判定
→ ログイン画面に飛ぶ
→ クッキーを元にサーバーと通信、認証されている
→ ログイン後のページに飛ぶ

つまり画面がチカチカするということと、画面更新するとトップページに毎回戻る感じになってしまいます。

Docker の設定(Laravel)

GitHub ページ に載せてみました。

Nuxt はローカルサーバーで起動してます。

npm -v
10.2.4

node のバージョン管理は volta を使ってます。

これは簡単で便利です。

まとめ

以上です。Docker の謎のエラーが一番詰まりました。

誰かの参考になればと思います。

このブログは広告のクリックによって支えられています。

参考になったという方はぜひ、ぜひ、ぜひぜひぜひともよろしくお願いします!

それでは!

人気記事

PHP7.4 + Laravel6 のプロジェクトを AWS EC2 にデプロイする

【laravel-breadcrumbs】Laravel でパンくずリストを実装する

フィードバックのお願い
この記事のフィードバックがありましたらYoutubeの適当な動画にコメントしていただいたり、お問い合わせからご連絡ください。