はじめに
こんにちは、ゆきおです。
こちらの記事で作った環境でAPIを実行する簡単なサンプルを作ろうと思います。
もともとあるUserモデルを使ってログイン、ログアウトを実装してみます。
バックエンド
まずSanctumのマイグレーションを行います
sail artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
sail artisan migrate
Sanctumの設定ファイルをプロジェクトにコピーし、新たに追加されるpersonal_access_tokens_tableをデータベースに反映させます。
次にデフォルトのUser.phpにSanctumのトレイトを追加します。
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
// 既存のコード
}
次に、ルートの設定をします。
Laravel11ではroutes/web.php、11以前はapi.phpに記述します。
<?php
use App\Http\Controllers\AuthController;
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
Route::post('/api/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::get('/api/user', [UserController::class, 'show']);
Route::post('/api/logout', [AuthController::class, 'logout']);
});
次にControllerを実装します。
認証するためのAuthController、Userの情報を取得して名前を表示するためのUserControllerを作成します。
(とりあえず動かしたいので型とかけっこう適当に書いてます
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function login(Request $request): \Illuminate\Http\JsonResponse
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (Auth::attempt($credentials)) {
$user = User::where('email', $request->email)->first();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json(['token' => $token], 200);
}
return response()->json(['message' => 'Invalid credentials'], 401);
}
public function logout(Request $request): \Illuminate\Http\JsonResponse
{
if ($request->user()->currentAccessToken() instanceof \Laravel\Sanctum\TransientToken) {
// Transient tokenの場合は削除せずに成功レスポンスを返す
return response()->json(['message' => 'Logged out successfully'], 200);
}
// 永続的なトークンの場合は削除する
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out successfully'], 200);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function show(Request $request)
{
return response()->json($request->user());
}
}
バックエンドの実装はこんなもんです。
Sanctumを使うことでベアラートークンによる安全な認証をシンプルに実装できます。
フロントエンド
次に見た目の実装をします。
これは前回の環境構築で作成したApp.vueを使用しています。
<template>
<div>
<div v-if="!token">
<input v-model="email" placeholder="Email" />
<input v-model="password" type="password" placeholder="Password" />
<button @click="login">Login</button>
</div>
<div v-else>
<p>Welcome, {{ user?.name }}</p>
<button @click="logout">Logout</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const email = ref('')
const password = ref('')
const token = ref(localStorage.getItem('token'))
const user = ref(null)
const login = async () => {
try {
const response = await axios.post('/api/login', { email: email.value, password: password.value })
token.value = response.data.token
localStorage.setItem('token', token.value)
await fetchUser()
} catch (error) {
console.error('Login failed', error)
}
}
const fetchUser = async () => {
try {
const response = await axios.get('/api/user', {
headers: { Authorization: `Bearer ${token.value}` }
})
user.value = response.data
} catch (error) {
console.error('Failed to fetch user', error)
}
}
const logout = async () => {
try {
await axios.post('/api/logout', {}, {
headers: { Authorization: `Bearer ${token.value}` }
})
token.value = null
user.value = null
localStorage.removeItem('token')
} catch (error) {
console.error('Logout failed', error)
}
}
if (token.value) {
fetchUser()
}
</script>
フロント側のエントリーポイントなどは前回の記事でやっていますが以下のようになっています
resources/js/app.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
welcome.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<div id="app"></div>
</body>
</html>
vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
});
最後に、Tinkerを使ってデータベースにユーザーデータを1つ入れておきます
sail artisan tinker
User::create(['name' => 'Test User', 'email' => 'user@example.com', 'password' => bcrypt('password123')]);
これでログイン、ログアウトが実装できたかと思いますのでサーバーを立ててテストします。
sail npm run dev
こんな感じで認証ができました。
おわり
今回は以上です。
ここから登録機能を追加したり、ほかにも色んな機能を実装していくと理解がより深まると思います。
例えばログアウト後はテキストボックスを空にするにはどうしたらいいだろう。とか
エラーが出た場合どういう表示をしたらいいだろう。とか
今回はそういったセキュリティやパフォーマンス、コードのリファクタなど全然やっていないサンプルで、ここからいくらでもアレンジや改良ができるような練習台を作成しました。
何かポートフォリオでも作ろうと思っている方や、アプリを改良していく練習がしたい方は参考にしてみてください。
最後までご覧いただきありがとうございました。