【備忘録】Laravel + Vueで管理者認証機能を実装する

## バージョン確認
PHP7.3
Laravel7.30
vue2.6.12

[Dockerを使ってローカル環境構築済み](https://qiita.com/kaba_farm/items/4e07dd14c4e3848d0658)
一般ユーザーの認証機能は[実装済み](https://qiita.com/kaba_farm/items/9d3a41e7eb2455c07998)


## 手順
* 一般ユーザーはusersテーブル、管理者画面はadminsテーブルを使う
* 管理者は`login_id`と`password`でログイン、ログアウトできるところまでを実装
* 便宜上管理者の新規登録機能も実装し、実務ではマスター管理などに応用する
* app.tsに、常に管理者の認証状態をvuexで保持するよう記述する
* コンポーネント化とcssによるスタイリングは割愛


## Laravel側の実装

```bash:/var/www/laravel
$ php artisan make:model Models/Admin -m
```

```php:database/migrations/2021_03_31_120856_create_admins_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAdminsTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('admins', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('login_id');
      $table->string('email');
      $table->timestamp('email_verified_at')->nullable();
      $table->string('password');
      $table->rememberToken();
      $table->timestamps();
      $table->softDeletes();
      $table->unique(['email', 'deleted_at'], 'users_email_deleted_at_unique');
      $table->unique(['login_id', 'deleted_at'], 'users_login_id_deleted_at_unique');
    });
  }

  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('admins');
  }
}
```

```bash:/var/www/laravel
$ php artisan migrate
```

```php:config/auth.php

'guards' => [
  'web' => [
    'driver' => 'session',
    'provider' => 'users',
  ],

  // 追加
  'admin' => [
    'driver' => 'session',
    'provider' => 'admins',
  ],

  'api' => [
    'driver' => 'token',
    'provider' => 'users',
    'hash' => false,
  ],
],

'providers' => [
  'users' => [
    'driver' => 'eloquent',
    'model' => App\Models\User::class,
  ],
  // 追加
  'admins' => [
    'driver' => 'eloquent',
    'model' => App\Models\Admin::class,
  ],

  // 'users' => [
  //     'driver' => 'database',
  //     'table' => 'users',
  // ],
],

'passwords' => [
  'users' => [
    'provider' => 'users',
    'table' => 'password_resets',
    'expire' => 60,
    'throttle' => 60,
  ],

  // 追加
  'admins' => [
    'provider' => 'admins',
    'table' => 'password_resets',
    'expire' => 60,
    'throttle' => 60,
  ],
],
```

```php:app/Models/Admin.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;

class Admin extends Authenticatable
{
  use Notifiable;
  use SoftDeletes;

  protected $table = 'admins';

  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = [
    'name', 'email', 'login_id', 'password',
  ];

  /**
   * The attributes that should be hidden for arrays.
   *
   * @var array
   */
  protected $hidden = [
    'password', 'remember_token',
  ];

  /**
   * The attributes that should be cast to native types.
   *
   * @var array
   */
  protected $casts = [
    'email_verified_at' => 'datetime',
  ];
}
```

```php:app/Http/Middleware/Authenticate.php

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Route;  // 追加

class Authenticate extends Middleware
{

  protected function redirectTo($request)
  {
    if (!$request->expectsJson()) {
      // 変更
      if (Route::is('admin.*')) {
        return route('admin.login');
      } else {
        return route('login');
      }
    }
  }
}
```

```php:app/Http/Middleware/RedirectIfAuthenticated.php
<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @param  string|null  $guard
   * @return mixed
   */
  public function handle($request, Closure $next, $guard = null)
  {
    if (Auth::guard($guard)->check()) {
　　　 // 変更
      if ($guard === 'user') {
        return redirect()->route('currentUser');
      } elseif ($guard === 'admin') {
        return redirect()->route('currentAdmin');
      }
    }

    return $next($request);
  }
}
```

```bash:/var/www/laravel
$ mkdir -p app/Http/Controllers/Admin/Auth
$ cp app/Http/Controllers/Auth/{RegisterController,LoginController}.php app/Http/Controllers/Admin/Auth/
```

```php:routes/api.php
Route::group(['middleware' => 'api'], function () {

  Route::get('/current_user', function () {
    return Auth::user();
  })->name('currentUser');

  Route::namespace('Auth')->group(function() {
    Route::post('/register', 'RegisterController@register')->name('register');
    Route::post('/login', 'LoginController@login')->name('login');

    Route::middleware('auth')->group(function() {
      Route::post('/logout', 'LoginController@logout')->name('logout');
    });
  });

  // 追加
  Route::get('/current_admin', function () {
    return Auth::guard('admin')->user();
  })->name('currentAdmin');

  Route::namespace('Admin')->prefix('admin')->name('admin.')->group(function () {
    Route::post('register', 'Auth\RegisterController@register')->name('register');
    Route::post('login', 'Auth\LoginController@login')->name('login');
    Route::post('logout', 'Auth\LoginController@logout')->name('logout');
  });

  Route::middleware('auth')->group(function () {
    // 一般認証が必要なAPI
  });
  
  Route::middleware('auth:admin')->group(function () {
    // 管理者認証が必要なAPI
  });

});
```

```php:app/Http/Controllers/Admin/Auth/RegisterController.php
<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\Admin;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;

class RegisterController extends Controller
{
  /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

  use RegistersUsers;

  protected function guard()
  {
    return Auth::guard('admin');
  }

  // 中略

  /**
   * Create a new controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest:admin');
  }

  /**
   * Get a validator for an incoming registration request.
   * 'users'を'admins'に変えるだけ
   * @param  array  $data
   * @return \Illuminate\Contracts\Validation\Validator
   */
  protected function validator(array $data)
  {
    return Validator::make($data, [
      'name' => ['required', 'string', 'max:255'],
      'login_id' => ['required', 'regex:/^[\w\-\._]+$/i', 'min:8', 'max:20', Rule::unique('admins', 'login_id')->whereNull('deleted_at')],
      'email' => ['required', 'string', 'email', 'max:255', Rule::unique('admins', 'email')->whereNull('deleted_at')],
      'password' => ['required', 'string', 'min:8', 'max:20', 'confirmed'],
    ]);
  } 

  /**
   * @param Request $request
   * @param Admin $admin
   * @return Admin
   */
  protected function registered(Request $request, $admin)
  {
    return $admin;
  }
```

```php:app/Http/Controllers/Admin/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use App\Models\Admin;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
  /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

  use AuthenticatesUsers;

  /**
   * Where to redirect users after login.
   *
   * @var string
   */
  protected $redirectTo = RouteServiceProvider::HOME;

  protected function guard()
  {
    return Auth::guard('admin');
  }


  /**
   * Create a new controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest:admin')->except('logout');
  }

  /**
   * @return string
   */
  public function username()
  {
    return 'login_id';
  }

  /**
   * @param Request
   * @param Admin $admin
   * @return Admin
   */
  protected function authenticated(Request $request, $admin)
  {
    return $admin;
  }

  /**
   * @param Request $request
   */
  protected function loggedOut(Request $request)
  {
    Auth::logout();
    $request->session()->regenerate();
    return response()->json();
  }
}
```

## Vue側の実装

```bash:~/workspace/myapp/resources/ts
$ cp types/Models/User.ts types/Models/Admin.ts \
> store/auth.ts store/admin.ts
```

```diff:resources/ts/types/Models/Admin.ts
- export type User = {
+ export type Admin = {
  id: number
  name: string
  [k: string]: any
} | null
```

```diff:resources/ts/store/admin.ts
- import { User } from '@/types/Models/User'
+ import { Admin } from '@/types/Models/Admin'
import { RegisterRequest, LoginRequest } from '@/types/Auth'
import { UNPROCESSABLE_ENTITY } from '@/util'
import router from '@/router'

export type State = {
-  user: User
+  admin: Admin
}

const state = {
-  user: null,
+  admin: null,
}

const getters = {
-  isLogin: (state: State): boolean => !!state.user,
-  userId: (state: State): number | null => (state.user ? state.user.id : null),
-  userName: (state: State): string => (state.user ? state.user.name : ''),
+  isLogin: (state: State): boolean => !!state.admin,
+  adminId: (state: State): number | null => (state.admin ? state.admin.id : null),
+  adminName: (state: State): string => (state.admin ? state.admin.name : ''),
}

const mutations = {
-   setUser(state: State, user: User): void {
-   state.user = user
+   setAdmin(state: State, admin: Admin): void {
+   state.admin = admin
  },
}

const actions = {
  async register(context, data: RegisterRequest): Promise<void> {
    await window.axios
-      .post('/api/register', data)
-      .then((response) => {
-        context.commit('setAdmin', response.data)
+      .post('/api/admin/register', data)
+      .then((response) => {
+        context.commit('setUser', response.data)
        context.commit(
          'error/setErrors',
          {
            messages: null,
            status: null,
          },
          { root: true }
        )
-        router.push('/mypage')
+        router.push('/admin/mypage')
      })
      .catch((err) => {
        if (err.response.status === UNPROCESSABLE_ENTITY) {
          context.commit(
            'error/setErrors',
            {
              messages: err.response.data.errors,
              status: err.response.status,
            },
            { root: true }
          )
        }
      })
  },

  async login(context, data: LoginRequest): Promise<void> {
    await window.axios
-      .post('/api/login', data)
-      .then((response) => {
+      .post('/api/admin/login', data)
+      .then((response) => {
-        context.commit('setUser', response.data)
+        context.commit('setAdmin', response.data)
        context.commit(
          'error/setErrors',
          {
            messages: null,
            status: null,
          },
          { root: true }
        )
-        router.push('/mypage')
+        router.push('/admin/mypage')
      })
      .catch((err) => {
        if (err.response.status === UNPROCESSABLE_ENTITY) {
          context.commit(
            'error/setErrors',
            {
              messages: err.response.data.errors,
              status: err.response.status,
            },
            { root: true }
          )
        } else {
          context.commit('error/setErrors',
          {
            messages: err.response,
            status: err.response.status,
          },
          { root: true }
          )
        }
      })
  },

  async logout(context): Promise<void> {
    await window.axios
-      .post('/api/logout')
+      .post('/api/admin/logout')
      .then((response) => {
-        context.commit('setUser', null)
-        router.push('/login')
+        context.commit('setAdmin', null)
+        router.push('/admin/login')
      })
      .catch((err) => {
        context.commit(
          'error/setErrors',
          {
            messages: err.response,
            status: err.response.status,
          },
          { root: true }
        )
      })
  },

-  async currentUser(context): Promise<void> {
+  async currentAdmin(context): Promise<void> {
    await window.axios
-      .get('/api/current_user')
-      .then((response) => {
-        const user = response.data || null
-        context.commit('setUser', user)
+      .get('/api/admin/current_admin')
+      .then((response) => {
+        const admin = response.data || null
+        context.commit('setAdmin', admin)
      })
      .catch((err) => {
        context.commit(
          'error/setErrors',
          {
            messages: err.response.data.errors,
            status: err.response.status,
          },
          { root: true }
        )
      })
  },
}

export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions,
}
```

```diff:resources/ts/store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'

import auth from './auth'
+ import admin from './admin'
import error from './error'
Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    auth,
+    admin,
    error
  },
})

export default store
```

```diff:resources/ts/app.ts
import Vue from 'vue'
// ルーティングの定義をインポートする
import router from './router'
// ルートコンポーネントをインポートする
import App from './App.vue'
import store from './store'

import bootstrap from './bootstrap'

bootstrap()

const createApp = async () => {
  await store.dispatch('auth/currentUser')
+  await store.dispatch('admin/currentAdmin')
  new Vue({
    el: '#app',
    router,
    store,
    render: (h) => h(App),
  })
}

createApp()
```

### view
```bash:~/workspace/myapp/resources/ts
$ mkdir -p layouts/admin pages/admin/mypage
$ touch layouts/admin/{Default,MyPageLayout}.vue \
> pages/admin/mypage/Index.vue

$ cp pages/{Register,Login}.vue pages/admin/
```

```vue:resources/ts/layouts/admin/Default.vue
<template>
  <div>
    <header>
      <nav>
        <ul v-if="!isLogin">
          <li><router-link tag="a" to="/admin/login">管理者ログイン</router-link></li>
          <li><router-link tag="a" to="/admin/register">管理者登録</router-link></li>
        </ul>
        <ul v-else>
          <li @click="logout">ログアウト</li>
        </ul>
      </nav>
    </header>
    <main>
      <div class="container">
        <router-view />
      </div>
    </main>
  </div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { mapGetters } from 'vuex'
@Component({
  computed: {
    ...mapGetters({
      isLogin: 'admin/isLogin'
    })
  }
})

export default class AdminLayout extends Vue {
  async logout(): Promise<void> {
    await this.$store.dispatch('admin/logout')
  }
}
</script>
```

```vue:resources/ts/layouts/admin/MyPageLayout.vue
<template>
  <div>
    <header>
      <nav>
        <ul v-if="!isLogin">
          <li><router-link tag="a" to="/admin/login">管理者ログイン</router-link></li>
          <li><router-link tag="a" to="/admin/register">管理者登録</router-link></li>
        </ul>
        <ul v-else>
          <li @click="logout">ログアウト</li>
        </ul>
      </nav>
    </header>
    <main>
      <div class="container">
        <router-view :admin="admin" />
      </div>
    </main>
  </div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { mapState, mapGetters } from 'vuex'
@Component({
  computed: {
    ...mapState({
      admin: state => state.admin.admin
    }),
    ...mapGetters({
      isLogin: 'admin/isLogin',
    }),
  }
})

export default class AdminMyPageLayout extends Vue {
  async logout(): Promise<void> {
    await this.$store.dispatch('admin/logout')
  }
}
</script>
```

```vue:resources/ts/pages/admin/Login.vue
<template>
<div>
  <h1>管理者ログイン</h1>
  <form @submit.prevent="login">
    <div v-for="(formItem, index) in submitData" :key="index">
      <p v-if="formItem.errorMessages">{{ formItem.errorMessages[0] }}</p>
      <input
        v-if="formItem.type==='text'"
        type="text"
        v-model="formItem.value"
        :placeholder="formItem.placeholder"
        @keyup="validation(formItem)"
        required
      >
      <input
        v-else-if="formItem.type==='password'"
        type="password"
        v-model="formItem.value"
        @keyup="validation(formItem)"
        :placeholder="formItem.placeholder"
        required
      >
    </div>
    <div>
      <button :disabled="disabled">ログイン</button>
    </div>
  </form>
</div>
</template>

<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator'
import { Form } from '@/types/Form'
import FormValidator from '@/mixins/formValidator'

@Component
export default class Login extends Mixins(FormValidator) {

  submitData: Form = {
    login_id: {
      name: 'login_id',
      type: 'text',
      value: '',
      rules: [(val: string) => !!val || 'ログインIDは必須です'],
      errorMessages: [],
      placeholder: 'login_id',
    },
    password: {
      name: 'password',
      type: 'password',
      value: '',
      rules: [(val: string) => !!val || 'パスワードは必須です'],
      errorMessages: [],
      placeholder: 'at least 8 chars.',
    },
  }

  async login(): Promise<void> {
    if (this.disabled) {
      Object.keys(this.submitData).forEach((key: string): void => {
        this.validation(this.submitData[key])
      })
    } else {
      const formData = new FormData()
      formData.append('login_id', this.submitData.login_id.value)
      formData.append('password', this.submitData.password.value)
      await this.$store.dispatch('admin/login', formData)
    }
  }

}
</script>
```

```vue:resources/ts/pages/admin/Register.vue
<template>
<div class="container">
  <h1>管理者登録</h1>
  <form @submit.prevent="register">
    <div v-for="(formItem, index) in submitData" :key="index">
      <p v-if="formItem.errorMessages">{{ formItem.errorMessages[0] }}</p>
      <input
        v-if="formItem.type==='text'"
        type="text"
        v-model="formItem.value"
        :placeholder="formItem.placeholder"
        @keyup="validation(formItem)"
        required
      >
      <input
        v-else-if="formItem.type==='email'"
        type="email"
        v-model="formItem.value"
        :placeholder="formItem.placeholder"
        @keyup="validation(formItem)"
        required
      >
      <input
        v-else-if="formItem.type==='password'"
        type="password"
        v-model="formItem.value"
        @keyup="validation(formItem)"
        :placeholder="formItem.placeholder"
        required
        >
    </div>
    <div>
      <button :disabled="disabled">管理者登録</button>
    </div>
  </form>
</div>
</template>

<script lang="ts">
import { Component, Mixins} from 'vue-property-decorator'
import { Form } from '@/types/Form'
import FormValidator from '@/mixins/formValidator'

@Component
export default class Register extends Mixins(FormValidator) {

  submitData: Form = {
    name: {
      name: 'お名前',
      type: 'text',
      value: '',
      rules: [
        (val: string) => !!val || '必須項目です',
        (val: string) => (val.length >= 2 && val.length <= 20) || '2文字以上20文字以下で設定してください',
      ],
      errorMessages: [],
      placeholder: 'your nickname',
    },
    email: {
      name: 'メールアドレス',
      type: 'email',
      value: '',
      rules: [
        (val: string) => !!val || '必須項目です',
        (val: string) => !!val.match(/^\w+[\w\-\._]*\w+@\w+[\w\-\._]*\.\w+[\w\-\._]*[A-Za-z]+$/i) || 'メールアドレスの形式が正しくありません'
      ],
      errorMessages: [],
      placeholder: 'sample@example.com',
    },
    login_id: {
      name: 'ログインID',
      type: 'text',
      value: '',
      rules: [
        (val: string) => !!val || '必須項目です',
        (val: string) => !!val.match(/^[\w\-\._]+$/g) || '半角英数字、「.」、「_」、「-」のみ使えます',
        (val: string) => val.length >= 8 && val.length <= 20 || '8文字以上20文字以下で入力してください'
      ],
      errorMessages: [],
      placeholder: 'login ID',
    },
    password: {
      name: 'パスワード',
      type: 'password',
      value: '',
      rules: [
        (val: string) => !!val || '必須項目です',
        (val: string) => !!val.match(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]+$/) || '半角小文字、半角大文字、数字をそれぞれ1種類以上含めてください',
        (val: string) => (val.length >= 8 && val.length <= 20) || '8文字以上20文字以下で設定してください',
      ],
      errorMessages: [],
      placeholder: 'at leeast 8 chars.',
    },
    password_confirmation: {
      name: 'パスワード（確認用）',
      type: 'password',
      value: '',
      rules: [
        (val: string) => !!val || '必須項目です',
        (val: string) => this.submitData.password.value === val || 'パスワードが一致しません'
      ],
      errorMessages: [],
      placeholder: 'confirm',
    },
  }

  async register(): Promise<void> {
    if (this.disabled) {
      Object.keys(this.submitData).forEach((key: string): void => {
        this.validation(this.submitData[key])
      })
    } else {
      const formData = new FormData()
      formData.append('name', this.submitData.name.value)
      formData.append('email', this.submitData.email.value)
      formData.append('login_id', this.submitData.login_id.value)
      formData.append('password', this.submitData.password.value)
      formData.append('password_confirmation', this.submitData.password_confirmation.value)
      await this.$store.dispatch('admin/register', formData)
    }
  }

}
</script>
```

```vue:resources/ts/pages/admin/mypage/Index.vue
<template>
<div>
  <p v-if="!!admin">{{ admin.name }}さん、管理者画面へようこそ</p>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
import { Admin } from '@/types/Models/Admin'

@Component
export default class AdminMyPageIndex extends Vue {
  @Prop({ type: Object, required: true, default: null })
  admin!: Admin
}
</script>
```

```ts:resources/ts/router.ts
import Vue from 'vue'
import VueRouter from 'vue-router'
// ページコンポーネントをインポートする
import Index from './pages/Index.vue'

// レイアウト
import DefaultLayout from './layouts/Default.vue'
import MyPageLayout from './layouts/MyPageLayout.vue'
+ import AdminDefaultLayout from './layouts/admin/Default.vue'
+ import AdminMyPageLayout from './layouts/admin/MyPageLayout.vue'

// ユーザー画面
import Login from './pages/Login.vue'
import Register from './pages/Register.vue'
import MyPageIndex from '@/pages/mypage/Index.vue'

// 管理者画面
+ import AdminLogin from '@/pages/admin/Login.vue'
+ import AdminRegister from '@/pages/admin/Register.vue'
+ import AdminMyPageIndex from '@/pages/admin/mypage/Index.vue'

import store from './store'
// VueRouterプラグインを使用する
Vue.use(VueRouter)

// パスとコンポーネントのマッピング
const routes = [
  {
    path: '/',
    component: DefaultLayout,
    children: [
      {
        path: '/',
        component: Index,
      },
      {
        path: '/register',
        component: Register,
        beforeEnter (to, from, next) {
          if (store.getters['auth/isLogin']) {
            next('/')
          } else {
            next()
          }
        }
      },
      {
        path: '/login',
        component: Login,
        beforeEnter (to, from, next) {
          if (store.getters['auth/isLogin']) {
            next('/')
          } else {
            next()
          }
        }
      },
    ],
  },
  {
    path: '/mypage',
    component: MyPageLayout,
    beforeEnter (to, from, next) {
      if (!store.getters['auth/isLogin']) {
        next('/login')
      } else {
        next()
      }
    },
    children: [
      {
        path: '/',
        component: MyPageIndex,
      }
    ],
  },

  // ↓追加
  {
    path: '/admin',
    component: AdminDefaultLayout,
    children: [
      {
        path: '/',
        component: AdminRegister,
        beforeEnter (to, from, next) {
          if (store.getters['admin/isLogin']) {
            next('/admin/mypage')
          } else {
            next('/admin/login')
          }
        }
      },
      {
        path: 'register',
        component: AdminRegister,
        beforeEnter (to, from, next) {
          if (store.getters['admin/isLogin']) {
            next('/admin/mypage')
          } else {
            next()
          }
        }
      },
      {
        path: 'login',
        component: AdminLogin,
        beforeEnter (to, from, next) {
          if (store.getters['admin/isLogin']) {
            next('/admin/mypage')
          } else {
            next()
          }
        }
      },
    ],
  },
  {
    path: '/admin/mypage',
    component: AdminMyPageLayout,
    beforeEnter (to, from, next) {
      if (!store.getters['admin/isLogin']) {
        next('/admin/login')
      } else {
        next()
      }
    },
    children: [
      {
        path: '/',
        component: AdminMyPageIndex,
      }
    ],
  },
]

const router = new VueRouter({
  mode: 'history',    //URL中の#(ハッシュ)を消す
  routes
})

export default router
```