Laravel

Laravel(Sanctum)とVue(Nuxt)でAPI認証をする方法

いつもご利用ありがとうございます。このブログは、広告費によって運営されています。

⇨ Laravel 記事の目次はこちら ⇨ Vue 記事の目次はこちら

Laravel(Sanctum)と Nuxt の auth-module を使って、API 認証の実装をしていきます。

はじめに

Sanctum とは?

Laravel8 からリリースされた Laravel の最も簡単な認証系のパッケージです。

以前までは、API の認証パッケージでは LaravelPassport というものがよく使われていましたが、機能過多でした。

しかし、機能過多なので「最初に使うにしては分かりにくい」ということで、

もっとシンプルに API 認証することが Sanctum で可能になりました。

LaravelSanctum 公式

Nuxt-Auth-Module とは?

Nuxt の認証情報を保持するための、標準パッケージです。

Vue の、Auth-module というパッケージを Nuxt で設定しやすいように作られているのがこのパッケージとなります。

nuxt/auth 公式

ざっくり流れの説明

①Laravel で認証の token を発行する

②Nuxt-auth で token を保持する

こういう流れになります。

 まずは、Laravel 側から設定していきましょう。

Laravel 側の設定

コマンドで必要なものを入れていきます。

プロジェクトの作成

composer create-project laravel/laravel poppotennis-laravel-api

Sanctum のインストール

composer require laravel/sanctum

ローカルサーバーを立てておきます

php artisan serve

ローカルサーバーがたった

Starting Laravel development server: http://127.0.0.1:8000

設定ファイルを変更できるようにする

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

database/migrations に新しいファイルが追加されました。

personalaccesstokens を変更することができます。

データベースの接続の設定は省略

人によって接続の仕方が違うと思うので省略します。

もし、データベースの接続方法が分からない場合は、一番簡単(個人的に)なこちらの記事でやってみてください

Laravel のデータベースの接続方法(MAMP の場合)

token を保存するデータベースの作成

personalaccesstokens テーブルを作成します(前のコマンドで生成されたファイルでテーブルを作るだけです)

コマンド

php artisan migrate

このコマンドで失敗する人は、データベースの接続がうまくいっていません。

パッケージのバージョン

"laravel/framework": "^8.75",
"laravel/sanctum": "^2.14",

App/Http/Kernel.php の変更

42 行目あたりの api の項目で、コメントアウトされている記述のコメントアウトを外します

'api' => [
  \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
  'throttle:api',
  \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

App/Http/Middleware/VerifyCsrfToken.php の変更

    protected $except = [
      'api/login'
    ];

ログインのための POST だけは認証していなくても許可をするようにしました。

User モデルで APItoken の認証をします的な設定をする

このような記述があることを確認してください。

多分、コマンドで勝手に記述がされています。

App/Models/User.php

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
  //以下略

テストユーザーのデータを作成する

Seeder という機能を使って、ユーザーのテストデータを作っていきます。

Laravel でテストデータを用意する方法(Seeder の使い方)

コマンドで Seeder ファイルを作成する

php artisan make:seeder UsersTableSeeder

database/seeders/UsersTableSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
//↓3行追記
use Hash;
use DB;
use App\Models\User;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $data = [
            [
                'name' => 'ポッポテニスくん',
                'email' => 'poppotennis@test.com',
                'password' => Hash::make('password')
            ],
        ];
        DB::table('users')->insert($data);
    }
}

上記の Seeder で

email:poppotennis@test.com

password:password

でログインできるユーザーが作成されます。

database/seeders/DatabaseSeeder.php を編集する

変更が必要な場所のみ

    public function run()
    {
        $this->call(UsersTableSeeder::class);
        // \App\Models\User::factory(10)->create();
    }

コマンド

今設定したクラスを読み込む

composer dump-autoload

データの生成

php artisan db:seed

Laravel でログイン機能をつける

ログイン用の route の作成

routes/api.php

use App\Http\Controllers\Api\Auth\LoginController;

Route::post('/login',[LoginController::class,'login']);

Laravel8 のルーティングの基本的な書き方

ログイン用の関数の作成

メールとパスワードの入力がある前提で、

ユーザーをメールで検索 ⇨ そのユーザーの保存されているパスワードと照合する

一番シンプルな関数を書きます。

<?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

//2行追記
use Hash;
use Illuminate\Validation\ValidationException;

class LoginController extends Controller
{
  //関数を追記
    public function login(Request $request)
    {
        $email = $request->email;
        $password = $request->password;

        $user = User::where('email', $email)->first();

          // Hash::check(今入力されたパスワード、DBに保存された暗号化済みのパスワード)
        if (! $user || ! Hash::check($password, $user->password)) {
           //ユーザーがいない|または|DBのパスワードと合致していれば
            throw ValidationException::withMessages([
                'email' => ['メールが違うか、パスワードが違うか'],
            ]);
        }

        $token = $user->createToken('token')->plainTextToken;
        //tokenという名前で返す
        return response()->json(compact('token'),200);
    }
}

API トークンの発行という項目に書いてあります

Nuxt 側の設定

プロジェクトの作成

yarn create nuxt-app poppotennis-nuxt-api

コマンドでローカルホスト

yarn dev

ローカルホストがたちました

  Nuxt @ v2.15.8                      │
   │                                       │
   │   ▸ Environment: development          │
   │   ▸ Rendering:   server-side          │
   │   ▸ Target:      static               │
   │                                       │
   │   Listening: http://localhost:3000/

nuxt-axios を入れる

コマンド

yarn add @nuxtjs/axios

nuxt.config.js の modules に追記

  modules: ["@nuxtjs/axios"],

axios のベースとなる URL(今回でいえば Laravel のローカルサーバーのアドレス)

nuxt.config.js に追記する

  publicRuntimeConfig: {
    axios: {
      baseURL: process.env.BASE_URL,
    },
  },

.env ファイルを作成する

Nuxt のプロジェクトディレクトリの直下に.env という名前でファイルを作成してください。

.env に追記する

BASE_URL=http://127.0.0.1:8000

ログインフォームを作る

pages/login/index.vue ファイルを作成する

Vuetify を使っているので、Vuetify 使っていない人は、v-text-field のところを input タグにしてください。

<template>
  <v-row>
    <v-col class="text-center">
      <v-text-field label="email" v-model="email"></v-text-field>
      <v-text-field label="password" v-model="password"></v-text-field>
      <v-btn @click="login" color="blue" outlined>ログイン</v-btn>
    </v-col>
  </v-row>
</template>

<script>
  export default {
    data() {
      return {
        email: "",
        password: "",
      };
    },
    methods: {
      login() {
        console.log("おした");
        this.$axios
          .$post("/api/login", {
            email: this.email,
            password: this.password,
          })
          .then((response) => {
            console.log(response);
          });
      },
    },
  };
</script>

ログインしてみる

poppotennis@test.com
password

を入力欄に入れてボタンを押す

コンソールに token が返却されていれば OK

{token: '6|XTSYN6HylafFkHfgWHxoODrrfA3kDjlptQFPChaB'}

以上動作確認でした。

あとは、Nuxt で token をうまく使って、認証機能を作ります

nuxt-auth-module を使う

コマンドでパッケージを入れる

この辺に書いてあります

yarn add @nuxtjs/auth-next

nuxt.config.js

modules に追記する。

さきほど axios でも追記しているので、modules の項目が二つにならないように、

以下のようにまとめてください。

  modules: ["@nuxtjs/axios", "@nuxtjs/auth-next"],
  //Modules: https://auth.nuxtjs.org/schemes/local
  auth: {
    strategies: {
      local: {
        token: {
          property: "token",
          global: true,
          // required: true,
          // type: 'Bearer'
        },
        user: {
          property: "user",
          // autoFetch: true
        },
        endpoints: {
          login: { url: "/api/login", method: "post" },
          logout: { url: "/api/logout", method: "post" },
          user: { url: "/api/user", method: "get" },
        },
      },
    },
  },

ボタンで動かした関数の中身を auth にする

async userLogin() {
      try {
        let response = await this.$auth.loginWith('local', { data: this.login })
        console.log(response)
      } catch (err) {
        console.log(err)
      }
    }

Laravel でユーザー情報を返す API を作る

api/user という URL でユーザー情報を返す API を作成します。

api/user という URL にする理由は、Nuxt.config.js のエンドポイントで設定しているからです。

ここの記述のことです。

    endpoints: {
          login: { url: "/api/login", method: "post" },
          logout: { url: "/api/logout", method: "post" },
          user: { url: "/api/user", method: "get" },
        },

api.php

Route::group(['middleware' => 'auth:sanctum'],function(){
    Route::get('/user',[UserController::class,'index']);
});

コマンドでコントローラーを作る

php artisan make:controller Api/UserController

App/Http/Controllers/Api/UserController.php

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

use App\Models\User;

class UserController extends Controller
{
    public function index(Request $request)
    {
        // $user = User::find(1);
        $user = $request->user();
        return response()->json(compact('user'),200);
    }
}

この URL を叩くと今ログインしているユーザーの情報を返すようになりました。

Nuxt 側でユーザー情報を表示する

template 内で使う時

<template>
  <div>
    <p>{{ $auth.loggedIn }}</p>
    <p>{{ $auth.user }}</p>
  </div>
</template>

表示

true(認証しているので。認証していない時はfalse)

{ "id": 1, "name": "ポッポテニスくん", "email": "poppotennis@test.com", "email_verified_at": null, "created_at": null, "updated_at": null }

script 内で使う時

this をつけるだけです。

<script>
export default {
  created(){
    console.log(this.$auth.user)
  }
}
</script>

ログインしていない人しかできない処理を書く

Laravel 側

.env に設定を書く

パスは、Nuxt のパスを書いてください

.env

SESSION_DOMAIN=http://127.0.0.1:3000
SANCTUM_STATEFUL_DOMAINS=http://127.0.0.1:3000

env を変えたら、コマンド

php artisan config:cache

この内容は config/session.php と、config/sanctum に反映されます。

api.php

post 用の行を追加

Route::group(['middleware' => 'auth:sanctum'],function(){
    Route::get('/user',[UserController::class,'index']);
    Route::post('/post',[PostController::class,'store']);
});

コントローラーを作る

php artisan make:controller Api/PostController

App/Http/Controller/Api/PostController.php に書く

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(Request $request)
    {
        $content = $request->content;
        //$user情報をとりたいときは
        $user = $request->user();
        // $userId = $request->user()->id;
        return response()->json(compact('content','user'),200);
    }
}

Nuxt に書く

<template>
  <v-btn @click="post">ポスト!</v-btn>
</template>
<script>
  export default {
    data() {
      return {
        content: "試しのポスト",
      };
    },
    methods: {
      post() {
        this.$axios
          .$post("/api/post", {
            content: this.content,
          })
          .then((response) => {
            console.log(response);
          });
      },
    },
  };
</script>

結果

content: "試しのポスト",
user: {id: 1, name: 'ポッポテニスくん', email: 'poppotennis@test.com', ....

以上です。お疲れ様でした!

まとめ

以上です。

クソ長いので記事にミスがある気がするので、以下の GitHub に載せています。

Laravel の GitHub

Nuxt の GitHub

感想・苦情は TwitterDM にご連絡ください。

それでは!

人気記事

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

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