Laravelやってみる#5―Airlockの導入と認証

Laravel 7.x

ぬにょす(挨拶)。

表題の通りですが、PHPフレームワークであるところのLaravelを使ってみようということで、やったこと・できたこと・できなかったこと等を自分の備忘録として残していきます。

#5の今回はLaravel Airlockを使ったユーザー認証を実装します。

スポンサーリンク

Laravel Airlockとは

Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small...

Laravel Airlock provides a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Airlock allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.

https://laravel.com/docs/7.x/airlock#introduction

SPAとかシンプルなトークンベースのAPI向けの軽量な認証システムらしいです。Laravel6のドキュメントにあったトークンベースの認証ガードがLaravel7では無くなっているので、その部分がAirlockというパッケージになったんでしょうか?

インストール

Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small...

composer でインストールしたのち、artisan コマンドでゴニョゴニョします。migrateはデータベースのあるゲストOSで実行しましょう。

composer require laravel/airlock php artisan vendor:publish --provider="Laravel\Airlock\AirlockServiceProvider" php artisan migrate
Code language: plaintext (plaintext)

設定

Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small...

リクエストを受け付けるSPAのドメインを設定するのですが、設定ファイル(config/airlock.php)では環境変数を参照しています。

'stateful' => explode(',', env('AIRLOCK_STATEFUL_DOMAINS', 'localhost')),
Code language: PHP (php)

なので .env ファイルにエントリーを追加します。

.env
AIRLOCK_STATEFUL_DOMAINS=ubuntu1804.local
Code language: plaintext (plaintext)

AirlockのミドルウェアをAPIミドルウェアグループに追加します。

app/Http/Kernel.php
protected $middlewareGroups = [ 'web' => [ ... ], 'api' => [ \Laravel\Airlock\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ];
Code language: PHP (php)

ログイン処理

Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small...

axios で /login にユーザー情報をPOSTしますが、ドキュメントによると最初に /airlock/csrf-cookie をリクエストしてCSRF保護を初期化すべし、とあります。

resources/js/views/LoginView.vue
methods: { login: function(){ axios .get("/airlock/csrf-cookie") .then(() => { axios .post("/login", this.form) .then(response => { this.$router.push({ name: "home" }); }) .catch(error => { console.log("Login Error", error); }); }) .catch(error => { console.log("Airlock Error", error); }); } }
Code language: JavaScript (javascript)

しかし試してみた範囲では、/airlock/csrf-cookie へのリクエストを省略しても動作に違いは見られませんでした。今回のようにバックエンドとフロントエンドが同一ドメインの場合は特に必要ないかもしれません。

コントローラーからのレスポンス変更

Laravelのスカフォールドで作成されたコントローラーでは、ログイン/ログアウトが成功した場合にリダイレクトするようになっています。そこで、AuthenticatesUsers トレイトのメソッドをオーバーライドして、JSONレスポンスを返すように変更します。

app/Http/Controllers/Auth/LoginController.php
use Illuminate\Http\Request; class LoginController extends Controller { /** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { if ($request->wantsJson()) { return response()->json($user); } } /** * The user has logged out of the application. * * @param \Illuminate\Http\Request $request * @return mixed */ protected function loggedOut(Request $request) { if ($request->wantsJson()) { return response()->json('Logout successful.'); } } }
Code language: PHP (php)

登録処理についても同様に RegistersUsers トレイトのメソッドをオーバーライドして、JSONレスポンスを返すように変更します。

app/Http/Controllers/Auth/RegisterController.php
use Illuminate\Http\Request; class RegisterController extends Controller { /** * The user has been registered. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function registered(Request $request, $user) { if ($request->wantsJson()) { return response()->json($user); } } }
Code language: PHP (php)

ログアウト処理

ログイン処理と似たような感じで実装しました。

resources/js/components/NavbarComponent.vue
methods: { logout: function(){ axios .get("/airlock/csrf-cookie") .then(() => { axios .post("/logout") .then(response => { this.$router.push({ name: "welcome" }); }) .catch(error => { console.log("Logout Error", error); }); }) .catch(error => { console.log("Airlock Error", error); }); } }
Code language: JavaScript (javascript)

AirlockでガードしたAPI

もともと定義されている /user API のミドルウェアを Airlock に変更します。

routes/api.php
// Route::middleware('auth:api')->get('/user', function (Request $request) { Route::middleware('auth:airlock')->get('/user', function (Request $request){ return $request->user(); });
Code language: PHP (php)

正しく保護されているかを検証するために、WelcomeページからこのAPIを呼んでみます。

resources/js/views/WelcomeView.vue
<template> ... <div> <b-button @click="onClick">Get User</b-button> <span>{{ message }}</span> </div> ... </template> <script> export default { data: function(){ return { message: "" }; }, methods: { onClick: function(){ this.message = ""; axios .get("/api/user") .then(response => { this.message = `Now ${response.data.email} is logged in.`; }) .catch(error => { this.message = `Oops! ${error.response.data.message}`; }); } } }; </script>
Code language: HTML, XML (xml)

実行結果

非ログイン時はエラーメッセージが表示され、ログイン時はアカウント名が表示されました。

ユーザー登録処理

ログイン処理と同様にフォームデータをPOSTして、ホーム画面にリダイレクトします。

resources/js/views/RegisterView.vue
methods: { register: function(){ axios .get("/airlock/csrf-cookie") .then(() => { axios .post("/register", this.form) .then(response => { this.$router.push({ name: "home" }); }) .catch(error => { console.log("Register Error", error); }); }) .catch(error => { console.log("Airlock Error", error); }); } }
Code language: JavaScript (javascript)

非ログイン状態での /home へのアクセス

Vueスクリプトでログイン後は /home へリダイレクトするようにしました。では、ログイン前に /home へアクセスするとどうなるでしょう。

ブラウザのアドレスバーに URL を直接打ち込んで読み込んだ場合は、Laravelフレームワークの auth ミドルウェアによる保護が働いて、ログイン画面にリダイレクトされます。

ところが、Vue Router での画面遷移はサーバーにリクエストするわけではないので、保護は効きません。ですので、Vue 側では独自にログイン状態により出力するリンクやリダイレクト先をコントロールする必要があります。

次回は

バリデーションメッセージの取得と表示を実装します。

コメント

タイトルとURLをコピーしました