はじめに
この記事は自分用です。
表記ミス・認識不足等の指摘は大歓迎ですが、決して内容を鵜呑みにしないでください。
やりたいこと
そもそもLaravel
+Vue.js
を使ってSPA
サービスを構築したかった。
サーバーと通信するならajax
しかねぇよなぁ?
→あっLaravelさんaxios
(エイクシオス)とかいうライブラリ標準で積んでるんすか、マジパネェっす
→そうなるとAPIファーストで構築しないとなぁ?
→このへんは結果をJSON
パースして返すだけっしょ
→しかしaxios
で通信するときどうやって認証取るんだ...?
→多分Laravel標準のセッション認証は使えないよねー?
→passport
なるものがあるらしい
ということでpassport入れてアクセストークン取得するまでの流れをメモ。
前提条件
Vue.jsのインストールが済んでいること。
インストールについてはこちらの記事を参考にどうぞ。
Passportとは
Laravelでは古典的なログインフォームによる認証は、簡単に実行できるようになっています。では、APIに関してはどうでしょうか? 通常APIでは、ユーザーの認証にトークンを使用し、リクエスト間のセッション状態は保持されません。Laravelアプリケーションのために、完全なOAuth2サーバの実装を提供するLaravel Passportを使えば、短時間で簡単にAPI認証ができます。Passportは、Alex Bilbieによりメンテナンスされている、League OAuth2サーバ上に構築しています。
ふむふむ。要するにLaravelで簡単にAPI認証したかったらpassport使えってことなのね。了解。
このドキュメントは皆さんが、OAuth2に慣れていることを前提にしています。OAuth2について知らなければ、この先を続けて読む前に、一般的な用語とOAuth2の機能について予習してください。
予習したけどわかりませんでした
何はともあれ、インストールしてみます。
予習に使ったサイト
大変勉強になりました。ありがとうございます。
手順
バックエンド
passportのインストール
公式ページ通りに進めていきます。
composer require laravel/passport
# 結果
# Your requirements could not be resolved to an installable set of packages.
早速エラーです。どうもpassportのバージョンが新しすぎてうまく入れられないようだ。
次の手順でバージョン指定してインストール。
# 改めてバージョン指定してインストール
composer require "laravel/passpor: 4.0.*"
# マイグレーションファイルが追加されるのでマイグレーション実行
php artisan migrate
# アクセストークン生成用の暗号キー生成
php artisan passport:install
Userモデルの修正
namespace App;
+ use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $table = 'users';
+ use HasApiTokens,
Notifiable;
app/Providers/AuthServiceProvide.phpの修正
namespace App\Providers;
+ use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot() {
$this->registerPolicies();
+ Passport::routes();
}
}
config/auth.phpの修正
return [
// +========
// | 省略
// +========
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
// 'driver' => 'token',
'driver' => 'passport',
'provider' => 'users',
],
],
// +========
// | 省略
// +========
];
'api' => [
- 'driver' => 'token',
+ 'driver' => 'passport',
'provider' => 'users',
],
公式ではここまで済めばあとは実装!という感じですが、もうワンアクション加えます。
app/Http/Kernel.php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// +========
// | 省略
// +========
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
+ \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
// +========
// | 省略
// +========
}
ただこの辺はMultiAuthで華麗に死ぬとかいう話もあるみたいだし、うーん。
イマイチ認証の仕組みが分かってない。勉強しないと。
フロントエンド
ここからはVue.js
辺りを入れてる前提で話してるから入れてない人は先に入れてね!
手順はこちら辺りを参照に。
resources/views/layouts/spa_app.blade.phpの修正
まずはレイアウトファイルから。
送信時にトークン(csrfToken
)を付与するよう設定を追記する。
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <meta name="csrf-token" content="{{ csrf_token() }}"> -->
<title>Laravel - SPA</title>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<script>
window.Laravel = {csrfToken: "{{ csrf_token() }}"};
</script>
</head>
<body>
<div id="app">
<div class="container">
<router-view></router-view>
</div>
</div>
</body>
<script src="{{ mix('js/app.js') }}"></script>
</html>
差分
- <!-- <meta name="csrf-token" content="{{ csrf_token() }}"> -->
<title>Laravel - SPA</title>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
+ <script>
+ window.Laravel = {csrfToken: "{{ csrf_token() }}"};
+ </script>
resources/assets/bootstrap.jsの修正
ここで言うbootstrap
とはCSSフレームワークではなく、「起動プロセスでコールされるプログラム」のことです。
最初Laravelをやり始めたとき、この辺りがごっちゃになってしまった。
フロントから送られてきたcsrfToken
を使ってaxios
でデータのやり取りを行えるように編集する。
window._ = require('lodash');
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
} catch (e) { }
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// let token = document.head.querySelector('meta[name="csrf-token"]');
let token = window.Laravel.csrfToken;
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
差分
- let token = document.head.querySelector('meta[name="csrf-token"]');
+ let token = window.Laravel.csrfToken;
assets/components/Index.vueの修正
最後にVueファイルを修正する。
今回は簡単に、認証されているかどうかの判定を行う関数を作ってみた。
<template>
<div>
<button @click="getUser">Am I logged in?</button>
<p v-if="user != []">{{ user.id }} : {{ user.name }}</p>
</div>
</template>
<script>
export default {
data() {
user: [],
},
methods: {
getUser: function() {
axios.get("/api/user")
.then(res => {
alert('Welcome, ' + response.data.name + '!!');
console.log(response.data);
this.user = response.data;
})
.catch(
alert('Sorry, you are not logged in.');
);
},
}
};
</script>
参考
ちなみに自前でトークン管理したい場合はこちらの記事のとおりにやればできました。
ご参考までに。
皆様、素敵な記事をありがとうございます。
この場を借りてお礼申し上げます。
所感
ほんっとうにこのやり方でセキュリティ大丈夫なんだろうか。心配。
ここまでやっといてなんだけど、JWT
とかの方が良さそう?的な記事をどっかで読んだ。
フロントエンド面白いけどわけわかめ...。
API周り...というより認証周り?はしっかり勉強しないといけないと言うことを改めて実感しました。