LoginSignup
26
28

More than 5 years have passed since last update.

【これを読めばわかる】Laravel と Vue.js のWEBページを動かすまでにやること

Last updated at Posted at 2018-10-18

この記事について

Laravel と Vue.js をつかったWEBサイトをつくる最低限の工程を書いています。
「これを読めばLaravel + Vue.js でページを作れる」となる程度に詳細を書いていきます。

composer インストール

Macでインストールする方法をチェック

Laravel インストール

以下で、Laravelのインストールとプロジェクト作成ができます。

composer create-project --prefer-dist laravel/laravel プロジェクト名

参考: laravelインストール公式ページ

npm インストール

git clone https://github.com/creationix/nvm.git ~/.nvm 
source ~/.nvm/nvm.sh
nvm install v9.5.0

ライブラリをインストール

cd ライブラリのディレクトリ
npm install

routes/web.php を修正

Route::get('/', function () {
-    return view('welcome');
+    return view('index');
});

index.blade.php を作成

resources/views/index.blade.php
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

  <meta name="theme-color" content="#282828">
  <meta name="msapplication-navbutton-color" content="#282828">

  <link rel="icon" href="{{ asset('/img/favicon.ico') }}" type="image/x-icon">
  <link rel="shortcut icon" href="{{ asset('/img/favicon.png') }}" type="image/png">
  <link rel="apple-touch-icon" href="{{ asset('/img/favicon.png') }}">

  <title>@yield('title') | {{ config('app.name') }}</title>
  <meta name="description" itemprop="description" content="@yield('description')">
  <meta property="og:type" content="website">
  <meta property="og:locale" content="ja_JP">
  <meta property="og:title" content="@yield('title') | {{ config('app.name') }}">
  <meta property="og:image" content="{{ asset('/img/favicon.png') }}">
  <meta property="og:description" content="@yield('description')">
  <meta property="og:url" content="">
  <meta property="og:site_name" content="">

  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:site" content="@" />
  <meta name="twitter:title" content="@yield('title') | {{ config('app.name') }}">
  <meta name="twitter:description" content="@yield('description')">
  <meta name="twitter:image" content="{{ asset('/img/favicon.png') }}">

  <meta name="csrf-token" content="{{ csrf_token() }}">
  <!-- <script src="{{ asset('js/app.js') }}"></script>
  <link href="{{ asset('css/app.css') }}" rel="stylesheet">
  <link href="{{ asset('css/reset.css') }}" rel="stylesheet"> -->

  <link rel="stylesheet" href="{{ mix('/css/app.css') }}">
</head>
<body>
    <div id="app">
        @yield('content')
    </div>
    <noscript>Javascriptを有効にしてください。</noscript>
    <script src=" {{ mix('js/app.js') }} "></script>
    <!-- @yield('js') -->
</body>
</html>

index.blade.phpのコードで、以下の部分が肝になります。

resources/views/index.blade.php
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ mix('/css/app.css') }}">
resources/views/index.blade.php
<script src=" {{ mix('js/app.js') }} "></script>

app.jsを修正

resources/js/app.js
require('./bootstrap');

window.Vue = require('vue');
+ import App from './app.vue'

const app = new Vue({
    el: '#app',
+   render: h => h(App),
});

参考: render: h => h(App)についてはこちらを参考に

app.vueを作成

resources/js/app.vue
<template>
  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-8">
        <div class="card card-default">
          <div class="card-header">{{ header }}</div>

          <div class="card-body">{{ body }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  mounted() {
    console.log('Component mounted.')
  },
  data() {
    return {
      header: "App Vue Header",
      body: "App Vue Body",
    }
  }
}
</script>

Laravel 開発サーバー起動

php artisan serve

Vueコンポーネントのコンパイル

npm run hot

JWT 認証

APIを使うときの認証はJWTを使うことにします。
jwt-auth というライブラリをつかっていきます。

インストール

composer require tymon/jwt-auth 1.0.0-rc3

Laravel 5.4以下の場合は、 config/app.php にServiceProviderを追加

'providers' => [
    ...
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]

configファイルを生成

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

config/jwt.php が作成されます。

シークレットキーを生成

php artisan jwt:secret

.envJWT_SECRET=...が書き込まれます。

参考

Userモデルを編集

<?php

namespace App;

+ use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

- class User extends Authenticatable
+ class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    // Rest omitted for brevity

+    /**
+     * Get the identifier that will be stored in the subject claim of the JWT.
+     *
+     * @return mixed
+     */
+    public function getJWTIdentifier()
+    {
+        return $this->getKey();
+    }

+    /**
+     * Return a key value array, containing any custom claims to be added to the JWT.
+     *
+     * @return array
+     */
+    public function getJWTCustomClaims()
+    {
+        return [];
+    }
}

APIのGuardを編集

'defaults' => [
-    'guard' => 'web',
+    'guard' => 'api',
    'passwords' => 'users',
],
...
'guards' => [
  'web' => [
    'driver' => 'session',
    'provider' => 'users',
  ],
  'api' => [
-    'driver' => 'token',
+    'driver' => 'jwt',
    'provider' => 'users',
  ],
],

認証routeを追加

routes/api.php
Route::group(['middleware' => 'api', 'prefix' => 'auth'], function ($router) {
  Route::post('login', 'AuthController@login');
  Route::post('logout', 'AuthController@logout');
  Route::post('refresh', 'AuthController@refresh');
  Route::post('me', 'AuthController@me');
});

AuthController作成

php artisan make:controller AuthController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;

class AuthController extends Controller
{
  /**
   * Create a new AuthController instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('auth:api', ['except' => ['login']]);
  }

  /**
   * Get a JWT via given credentials.
   *
   * @return \Illuminate\Http\JsonResponse
   */
  public function login()
  {
    $credentials = request(['uid', 'password']);

    if (! $token = auth()->attempt($credentials)) {
      return response()->json(['error' => 'Unauthorized'], 401);
    }

    return $this->respondWithToken($token);
  }

  /**
   * Get the authenticated User.
   *
   * @return \Illuminate\Http\JsonResponse
   */
  public function me()
  {
    return response()->json(auth()->user());
  }

  /**
   * Log the user out (Invalidate the token).
   *
   * @return \Illuminate\Http\JsonResponse
   */
  public function logout()
  {
    auth()->logout();

    return response()->json(['message' => 'Successfully logged out']);
  }

  /**
   * Refresh a token.
   *
   * @return \Illuminate\Http\JsonResponse
   */
  public function refresh()
  {
    return $this->respondWithToken(auth()->refresh());
  }

  /**
   * Get the token array structure.
   *
   * @param  string $token
   *
   * @return \Illuminate\Http\JsonResponse
   */
  protected function respondWithToken($token)
  {
    return response()->json([
      'access_token' => $token,
      'token_type' => 'bearer',
      'expires_in' => auth()->factory()->getTTL() * 60
    ]);
  }
}

認証する

http://example.dev/api/auth/login で認証されるようになりました。

Laravel APIで uid を認証

vue.js でIDトークンを取得

firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
  // Send token to your backend via HTTPS
  // ...
}).catch(function(error) {
  // Handle error
});

参照

Vue.js から Laravel API にIDトークンを送信

Authorization: Bearer {IDトークン} をヘッダーにつけて送信する。

Laravel 側でIDトークンを確認

php用のfirebase サードパーティ sdk

composer require kreait/firebase-php ^4.18

参考

public key をキャッシュするためsymfony/cacheをインストール

composer require symfony/cache

上で作成した認証用のAuthControllerを変更していきたいと思います。

use Kreait\Firebase\Factory;
use Kreait\Firebase\ServiceAccount;
use Symfony\Component\Cache\Simple\FilesystemCache;

class AuthController extends Controller
{
  ... 

  public function login()
  {
    // email じゃなくて uid を使いたいので email を削除
    $credentials = request(['password']);

    // AuthorizationヘッダーからFirebaseのIDトークンを取得
    $headers = getallheaders();
    if (!isset($headers['Authorization'])) {
      return response()->json(['error' => self::ERROR_NO_ID_TOKEN], 401);
    }
    $authorization = $headers['Authorization'];
    $explodedAuthorization = explode(' ', $authorization);
    $idTokenString = $explodedAuthorization[1];
    if (!$idTokenString) {
      return response()->json(['error' => self::ERROR_NO_ID_TOKEN], 401);
    }

    // IDトークンを確認してUIDを取得
    $cache = new FilesystemCache();
    $serviceAccount = ServiceAccount::fromJsonFile('/google-service-account.json');
    $firebase = (new Factory)->withServiceAccount($serviceAccount)->withVerifierCache($cache)->create();
    try {
      $verifiedIdToken = $firebase->getAuth()->verifyIdToken($idTokenString);
    } catch (InvalidToken $e) {
        return response()->json(['error' => $e->getMessage()], 401);
    }
    $credentials['uid'] = $verifiedIdToken->getClaim('sub');

    // ユーザー未登録なら登録
    $user = User::where('uid', '=', $credentials['uid'])->first();
    if (!$user) {
      $result = User::create([
        'uid' => $credentials['uid'],
        'password' => Hash::make($credentials['password']),
      ]);
    }

    // JWT取得
    if (!$token = auth()->attempt($credentials)) {
      return response()->json(['error' => 'Unauthorized'], 401);
    }

    return $this->respondWithToken($token);
  }

管理画面

laravel-adminという管理画面ライブラリを使います。

初期設定

# composer
composer require encore/laravel-admin
# assets, config(config/admin.php) を作成
php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
# install
php artisan admin:install

コントローラー作成

# コントローラ作成
php artisan admin:make UserController --model=App\\User
# app/Admin/routes.php にルートを追加
$router->resource('demo/users', UserController::class);

メニューにパスを追加するには、admin/auth/menuにアクセスして追加する。

参考

ファイルアップロード設定

ファイルのアップロード先のルートパスと、ファイルのアクセスURLを設定。
public/uploadsにファイルがアップロードされ、http://xxxx/uploadsでファイルにアクセスできるようにする。

config/filesystems.php
'disks' => [
    ... ,

    'admin' => [
        'driver' => 'local',
        'root' => public_path('uploads'),
        'visibility' => 'public',
        'url' => env('APP_URL').'/uploads',
    ],
],

以下を設定すると、画像ファイルはpublic/uploads/imageに、そのほかのファイルはpublic/uploads/fileにアップロードされます。
それぞれhttp://xxxx/uploads/imagehttp://xxxx/uploads/fileでアクセスできます。

config/admin.php
'upload'  => [

    'disk' => 'admin',

    'directory'  => [
        'image'  => 'image',
        'file'   => 'file',
    ],
],

アップロード用のフォームを作成する場合は、コントローラーを編集します。

ExamleController.php
protected function form()
{
    $form = new Form(new Example);
    // uploads/image 直下にアップロードしたい場合
    $form->image('image_url', '画像');
    // uploads/image/xxxx にアップロードしたい場合
    $form->image('image_url', '画像')->move('image/xxxx');
}

moveを使うと、config/filesystems.phpdisks.admin.root以下のパスを指定することになるので、imageを定数にしてこんな風にするのが良いかと思います。

config/admin.php
'upload'  => [
    'directory'  => [
        'image'  => env('UPLOAD_IMAGE_PATH'),
ExamleController.php
$form->image('image_url', '画像')->move(env('UPLOAD_IMAGE_PATH') . '/xxxx');

アップロードしたファイルの表示は以下のようにします。

ExamleController.php
protected function grid()
{
    $grid = new Grid(new Example);
    $grid->image_url('画像')->image();
    ...
}

参考

26
28
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
26
28