[Laravel5.5] (暫定版)Passportを使って自分自身のAPIサーバーから情報を取得する

# はじめに
この記事は自分用です。
表記ミス・認識不足等の指摘は大歓迎ですが、決して内容を鵜呑みにしないでください。

# やりたいこと
そもそも`Laravel`+`Vue.js`を使って[**`SPA`**](https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a)サービスを構築したかった。

サーバーと通信するなら`ajax`しかねぇよなぁ？
→あっLaravelさん[**`axios`**](https://www.yoheim.net/blog.php?q=20170801)（エイクシオス）とかいうライブラリ標準で積んでるんすか、マジパネェっす
→そうなるとAPIファーストで構築しないとなぁ？
→このへんは結果を`JSON`パースして返すだけっしょ
→しかし`axios`で通信するときどうやって認証取るんだ...？
→多分Laravel標準のセッション認証は使えないよねー？
→`passport`なるものがあるらしい

ということでpassport入れてアクセストークン取得するまでの流れをメモ。

# 前提条件
Vue.jsのインストールが済んでいること。
インストールについては[**こちらの記事**](https://qiita.com/tosite0345/items/0f8aec4d987389c55766)を参考にどうぞ。

# Passportとは
> Laravelでは古典的なログインフォームによる認証は、簡単に実行できるようになっています。では、APIに関してはどうでしょうか？　通常APIでは、ユーザーの認証にトークンを使用し、リクエスト間のセッション状態は保持されません。Laravelアプリケーションのために、完全なOAuth2サーバの実装を提供するLaravel Passportを使えば、短時間で簡単にAPI認証ができます。Passportは、Alex Bilbieによりメンテナンスされている、League OAuth2サーバ上に構築しています。

ふむふむ。要するにLaravelで簡単にAPI認証したかったらpassport使えってことなのね。了解。

> このドキュメントは皆さんが、OAuth2に慣れていることを前提にしています。OAuth2について知らなければ、この先を続けて読む前に、一般的な用語とOAuth2の機能について予習してください。

予習したけどわかりませんでした:innocent:
何はともあれ、インストールしてみます。

----
## 予習に使ったサイト
+ [**OAuth 2.0 全フローの図解と動画**](https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f)
+ [**一番分かりやすい OAuth の説明**](https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be)
+ [**API認証(Passport)機能の動作確認**](http://www.dn-web64.com/archives/web/laravel_passport/)

大変勉強になりました。ありがとうございます。

# 手順

## バックエンド
### passportのインストール

公式ページ通りに進めていきます。

```bash:console
composer require laravel/passport

# 結果
# Your requirements could not be resolved to an installable set of packages.
```

早速エラーです。どうもpassportのバージョンが新しすぎてうまく入れられないようだ。
次の手順でバージョン指定してインストール。


```bash:console
# 改めてバージョン指定してインストール
composer require "laravel/passpor: 4.0.*"

# マイグレーションファイルが追加されるのでマイグレーション実行
php artisan migrate

# アクセストークン生成用の暗号キー生成
php artisan passport:install
```

### Userモデルの修正

```diff:app/user.php
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の修正

```diff:app/Providers/AuthServiceProvider.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の修正

```php:config/auth.php
return [
    // +========
    // |  省略
    // +========
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
         // 'driver' => 'token',
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],
    // +========
    // |  省略
    // +========
];
```

```diff:差分
        'api' => [
-           'driver' => 'token',
+           'driver' => 'passport',
            'provider' => 'users',
        ],
```

公式ではここまで済めばあとは実装！という感じですが、もうワンアクション加えます。

### app/Http/Kernel.php

```diff: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で華麗に死ぬ**](https://qiita.com/kroton/items/4711de8c9b5913532de6)とかいう話もあるみたいだし、うーん。
イマイチ認証の仕組みが分かってない。勉強しないと。

## フロントエンド

ここからは`Vue.js`辺りを入れてる前提で話してるから入れてない人は先に入れてね！
手順は[**こちら**](https://qiita.com/tosite0345/items/0f8aec4d987389c55766)辺りを参照に。

### resources/views/layouts/spa_app.blade.phpの修正

まずはレイアウトファイルから。
送信時にトークン（`csrfToken`）を付与するよう設定を追記する。

```html:resources/views/layouts/spa_app.blade.php
<!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>
```

差分

```diff:差分
- <!-- <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`でデータのやり取りを行えるように編集する。

```js:resources/assets/bootstrap.js

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');
}
```

差分

```diff:差分
- let token = document.head.querySelector('meta[name="csrf-token"]');
+ let token = window.Laravel.csrfToken;
```

### assets/components/Index.vueの修正
最後にVueファイルを修正する。
今回は簡単に、認証されているかどうかの判定を行う関数を作ってみた。
 
```vue:assets/components/Index.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>
```

# 参考

+ [**Laravel Passportで自身のJavaScriptからAPIを利用する方法**](https://s8a.jp/laravel-passport-javascript-api#meta%E3%82%BF%E3%82%B0%E3%82%92%E7%94%A8%E6%84%8F%E3%81%97%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%98%E3%83%83%E3%83%80%E3%83%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)
+ [**VUETIFUL**](https://vuetiful.wordpress.com/category/vuetiful-project/)
+ [**LARAVEL 5.3 で PASSPORTを試す**](https://blog.hinaloe.net/2016/09/15/try-passport-laravel-5-3/)

ちなみに自前でトークン管理したい場合はこちらの記事のとおりにやればできました。
ご参考までに。

+ [**Laravel+Vue.jsでトークン認証してデータを取得する**](http://www.webopixel.net/php/1343.html)

皆様、素敵な記事をありがとうございます。
この場を借りてお礼申し上げます。

# 所感
ほんっとうにこのやり方でセキュリティ大丈夫なんだろうか。心配。
ここまでやっといてなんだけど、`JWT`とかの方が良さそう？的な記事をどっかで読んだ。
フロントエンド面白いけどわけわかめ...。
API周り...というより認証周り？はしっかり勉強しないといけないと言うことを改めて実感しました。