Laravel API でのユーザの認証は Sanctum パッケージを利用すると効率的に実装ができます.Sanctum パッケージはプロジェクトの新規作成と同時にインストールされているはずです.Sanctum パッケージがインストールされていない場合や,Sandtum に必要なファイルを削除してしまっている場合などは次のコマンドで Sanctum をインストールします.
vagrant@ubuntu2204 CommentAPI $ php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" ⏎
INFO Publishing assets.
Copying directory [vendor/laravel/sanctum/database/migrations] to [database/migrations] DONE
File [config/sanctum.php] already exists ..................... SKIPPED
vagrant@ubuntu2204 CommentAPI $
次に,Kernel.php を修正して Sanctum を有効化します.具体的には 'api'
の設定項目で Sanctum の設定がコメントになっているので,このコメントを解除します.
app/Http/Kernel.php
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
現在のルート定義を確認するとコメントの機能に関する幾つかのルートが次のとおり存在しています.
routes/api.php (抜粋)
Route::get('/comments', [CommentController::class, 'index']) -> name('comments.index');
Route::get('/comments/{comment_id}', [CommentController::class, 'show']) -> name('comments.show');
Route::post('/comments', [CommentController::class, 'store']) -> name('comments.store');
Route::put('/comments/{comment_id}', [CommentController::class, 'update']) -> name('comments.update');
Route::delete('/comments/{comment_id}', [CommentController::class, 'destroy']) -> name('comments.destroy');
これらの全ての機能を利用するときに認証を必要としたいので,auth:sanctum
のmiddleware
で囲います.さらに,ログインのルートも定義します.なお,「ログイン」という名称を使っていますが,「トークンの発行」という意味合いで利用するので,名前は変更した方が直感的かもしれません.
routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CommentController;
use App\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::group(['middleware' => 'auth:sanctum'], function(){
Route::get('/comments', [CommentController::class, 'index']) -> name('comments.index');
Route::get('/comments/{comment_id}', [CommentController::class, 'show']) -> name('comments.show');
Route::post('/comments', [CommentController::class, 'store']) -> name('comments.store');
Route::put('/comments/{comment_id}', [CommentController::class, 'update']) -> name('comments.update');
Route::delete('/comments/{comment_id}', [CommentController::class, 'destroy']) -> name('comments.destroy');
});
Route::post('login', [UserController::class, 'login']);
次に UserController を作成します.
vagrant@ubuntu2204 CommentAPI $ php artisan make:controller UserController ⏎
INFO Controller [app/Http/Controllers/UserController.php] created successfully.
vagrant@ubuntu2204 CommentAPI $
app/Http/Controllers/UserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
class UserController extends Controller
{
function login(Request $request)
{
$user = User::where('email', $request->email)->first();
if (!$user || !password_verify($request->password, $user->password)) {
return response([
'message' => ['認証情報が異なります']
], 404);
}
$token = $user->createToken('comments-api-token')->plainTextToken;
$response = [
'user' => $user,
'token' => $token
];
return response($response, 201);
}
}
コマンドを使ってルートの定義を確認します.
vagrant@ubuntu2204 CommentAPI $ php artisan route:list GET|HEAD / .......................................................... POST _ignition/execute-solution ignition.executeSolution › Spati… GET|HEAD _ignition/health-check ignition.healthCheck › Spatie\Larave… POST _ignition/update-config ignition.updateConfig › Spatie\Lara… GET|HEAD api/comments ...... comments.index › CommentController@index POST api/comments ...... comments.store › CommentController@store GET|HEAD api/comments/{comment_id} comments.show › CommentController… PUT api/comments/{comment_id} comments.update › CommentControll… DELETE api/comments/{comment_id} comments.destroy › CommentControl… POST api/login ............................. UserController@login GET|HEAD api/user ................................................... GET|HEAD sanctum/csrf-cookie sanctum.csrf-cookie › Laravel\Sanctum … Showing [12] routes vagrant@ubuntu2204 CommentAPI $
ルートの確認ができたので,curl
コマンドを使って,(1) 認証情報を付与せずに閲覧,(2) 正しい認証情報を付与して閲覧,を順番に試みます.どちらの場合もエラーになりました.
C:\Users\Rinsaka>curl http://192.168.56.101:8000/api/comments/1/ ⏎ <!DOCTYPE html> <html lang="en" class="auto"> <!-- Symfony\Component\Routing\Exception\RouteNotFoundException: Route [login] not defined. in file /home/vagrant/Documents/laravel/CommentAPI/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 479 ...(以下略)... C:\Users\Rinsaka>curl -u a@sample.com:abc http://192.168.56.101:8000/api/comments/1/ ⏎ <!DOCTYPE html> <html lang="en" class="auto"> <!-- Symfony\Component\Routing\Exception\RouteNotFoundException: Route [login] not defined. in file /home/vagrant/Documents/laravel/CommentAPI/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 479 ...(以下略)...
Web ブラウザで接続しても閲覧できません.
Postman で認証情報を付与しない場合も閲覧できません.
Laravel で Sanctum を使った場合はユーザ名とパスワードで API への接続を認証するわけではありません.実はユーザごとにトークンを発行して,そのトークンで認証を行います.まず,現時点ではデータベースの personal_access_token テーブルにデータが登録されていないことを確認します.
sqlite> .tables ⏎ comments migrations personal_access_tokens failed_jobs password_reset_tokens users sqlite> SELECT * FROM personal_access_tokens; ⏎ sqlite>
ログインのための URI (/api/login/) に POST メソッドでメールアドレスとパスワードの正しい組み合わせを送信するとトークンが発行されます.ここで表示されたトークンは確実にメモ(コピー)しておく必要があります.
C:\Users\Rinsaka>curl -X POST -d "email=a@sample.com" -d "password=abc" http://192.168.56.101:8000/api/login/ ⏎ {"user":{"id":1,"name":"A. Sample","email":"a@sample.com","email_verified_at":null,"created_at":"2023-11-02T15:01:01.000000Z","updated_at":"2023-11-02T15:01:01.000000Z"},"token":"1|LKP6Mb8mQQ7d0TJpRoxpsk8NoWFeDJvEPcNPu0gscf82b730"} C:\Users\Rinsaka>
データベースで personal_acces_tokens テーブルを検索してトークンが発行されていることを確認します.ただし,データベースのテーブルにはトークンそのものが格納されているわけではなく,ハッシュ化されて保存されていることに注意してください.つまり,上で発行したトークンをハッシュ値から復元することはできません.
sqlite> SELECT * FROM personal_access_tokens; ⏎ id|tokenable_type|tokenable_id|name|token|abilities|last_used_at|expires_at|created_at|updated_at 1|App\Models\User|1|comments-api-token|0c94ec67889ac45b2963e7876260ce7452c8b3880963f5eb2a72aa1019e11324|["*"]|||2023-12-18 10:18:54|2023-12-18 10:18:54 sqlite>
トークンを取得できたので,そのトークンを利用してコメントの閲覧と投稿を行います.コマンド curl
でトークンを付与するには -H
オプションを利用して Bearer
トークンとして次のように指定します.もちろんトークンは上の作業で発行されたものを指定してください.
C:\Users\Rinsaka>curl -H "Authorization: Bearer 1|LKP6Mb8mQQ7d0TJpRoxpsk8NoWFeDJvEPcNPu0gscf82b730" http://192.168.56.101:8000/api/comments/1/ ⏎ {"comment":{"id":1,"title":"最初のコメント","body":"最初のコメントです!","updated_at":"2023-10-02T10:10:10.000000Z"}} C:\Users\Rinsaka> C:\Users\Rinsaka>curl -X POST -d "title=auth sanctum" -d "body=token test" -H "Authorization: Bearer 1|LKP6Mb8mQQ7d0TJpRoxpsk8NoWFeDJvEPcNPu0gscf82b730" http://192.168.56.101:8000/api/comments/ ⏎ {"comment":{"id":101,"title":"auth sanctum","body":"token test","updated_at":"2023-12-18T10:30:01.000000Z"}} C:\Users\Rinsaka>
次の様にすると Postman でも認証情報を付与することができます.まず,「認証」のページを開き,タイプで「Bearer トークン」を選びます.
次に,正しいトークンを入力(ペースト)します.
コメントの個別表示の URI を入力して「送信」ボタンを押下すると,1件のコメント情報を取得できました.
新規投稿の場合は「POST」メソッドを選択してトークンも設定します.
「パラメーター」のページを開いて「キー」と「値」を設定して「送信」ボタンを押下します.
新規投稿に成功すると画面下部のボックスに結果が表示されます.
コメントを一覧で取得すると今 Postman で投稿したコメントと直前に curl
コマンドで投稿したコメントを確認できました.
これでトークンによる認証を必要とする API を実装することできました.PUT メソッドや DELETE メソッドも同じ方法でトークンを与えれば実行できることも確認してください.