21
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-03-13

はじめに

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

やりたいこと

そもそも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の機能について予習してください。

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


予習に使ったサイト

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

手順

バックエンド

passportのインストール

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

console
composer require laravel/passport

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

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

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

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

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

Userモデルの修正

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の修正

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の修正

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

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)を付与するよう設定を追記する。

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>

差分

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

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

差分

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

assets/components/Index.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>

参考

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

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

所感

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

21
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?