ぬにょす(挨拶)。
表題の通りですが、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
{
protected function authenticated (Request $request, $user)
{
if ($request->wantsJson()) {
return response()->json($user);
}
}
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
{
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: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 側では独自にログイン状態により出力するリンクやリダイレクト先をコントロールする必要があります。
次回は バリデーションメッセージの取得と表示を実装します。
コメント