11
9

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.

laravel+vueでrole,permissionごとにいろいろやりたい→laravel-permissionを使ってみる!

Last updated at Posted at 2019-09-13

# はじめに
 laravel+vueでどうroleやpermissionを使ったものかよくわからなかったため、
 調べた結果を少しでも残せればと思い書きました。

 間違っているところもたくさんあると思うので、よければ指摘してやってください。

# 環境
 php 7.2.12
 laravel 6.0.3

# 何を作るか

 admin,userの二種類用意し、
 adminには隠しページに行ける許可すべてのuserを閲覧できる許可userの削除の許可
 userにはすべてのuserを閲覧できる許可のみを与えます。

1. laravel-permissionを使おう!

##1-1 最初の設定

 laravel new お好みで
 から.envのDB設定までは省略します。

1-2 make:auth(laravel 6.0では消滅しているので別の方法を使う)

 6.0以前

php artisan make:auth

 6.0から 

composer require laravel/ui

php artisan ui vue --auth

 このあと6.0ならnpm installnpm run devをやってください。

1-3 laravel-permissionのインストール

composer require spatie/laravel-permission

config/app.phpに追加

config/app.php
  'providers' => [
   // ...
   Spatie\Permission\PermissionServiceProvider::class,
];

そのあとmigrationをします。

 php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"

 php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"

 php artisan migrate

忘れずにUserModelにHasRolesトレイトを追加しておきましょう。

user.php
class User extends Authenticatable
{
    use Notifiable;
    use HasRoles;//これを追加!
}

1-4 seedingによりRoleとPermissionを設定する

 roleadminuserの二つ、
 permissionread_hiddenpageread_allusersdelete_userの三つとします。
 

role permission
user read_allusers
admin read_allusers,delete_user,read_hiddenpage
という風にしていきます。

まずroleTableからseeding

seeder RoleTableSeeder
RoleTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;//ここを忘れないように!

class RoleTableSeeder extends Seeder
{
   /**
    * Run the database seeds.
    *
    * @return void
    */
   public function run()
   {
       $roles = [
           "admin",
           "user"
       ];
       foreach ($roles as $role) {
           Role::create(["name" => $role]);
       }
   }
}

permissionTable

php artisan make:seeder RoleTableSeeder

PermissionTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;

class PermissionTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $permissions = [
            "read_hiddenpage",
            "read_allusers",
            "delete_user"
        ];
        foreach ($permissions as $permission) {
            Permission::create(["name" => $permission]);
        }
    }
}

RoleHasPermissionTable,ここで各roleにpermissionを与えていきます。

php artisan make:seeder RoleHasPermissionTableSeeder

RoleHasPermissionTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;

class RoleHasPermissionTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //admin
        $permissions = [
            "read_hiddenpage",
            "read_allusers",
            "delete_user"
        ];
        //一時変数使いたくないならtapで
        $role = Role::findByName("admin");
        $role->givePermissionTo($permissions);

        //user
        $permissions = [
            "read_alluser"
        ];
        $role = Role::findByName("user");
        $role->givePermissionTo($permissions);
    }
}

最後にUserをadminとuserの二種作ります。

 php artisan make:seeder UserTableSeeder

UserTableSeeder.php
<?php

use App\User;
use Illuminate\Database\Seeder;


class UserTableSeeder extends Seeder
{
   /**
    * Run the database seeds.
    *
    * @return void
    */
   public function run()
   {
       //admin
       $user = User::create([
           "name" => "管理者",
           "email" => "admin@test",
           "password" => Hash::make('admin'),
       ]);
       $user->assignRole("admin");

       //user
       $user = User::create([
           "name" => "ユーザー",
           "email" => "user@test",
           "password" => Hash::make('user'),
       ]);
       $user->assignRole("user");
   }
}

1-5 Seedingの実行

 ```
composer dump-autoload
php artisan db:seed --class=PermissionTableSeeder
php artisan db:seed --class=RoleTableSeeder
php artisan db:seed --class=RoleHasPermissionTableSeeder
php artisan db:seed --class=UserTableSeeder


 
#  2.Vue側の設定

## 2-1 VueComponentにとりかかろう!
home.blade.phpをVueが使えるように変更しておく

```php:home.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link rel="stylesheet" href="{{asset('css/app.css')}}">
    <title>test</title>
</head>
<body>
    <div id="app">
    <example-component></example-component>
    </div>
    <script src="{{asset('js/app.js')}}"></script>
</body>
</html>

このままじゃlogoutができないので、mountしたExampleComponentにlogoutMethodを作ってあげる。

axios.post(/logout)すれば良くて、これでLoginController@logoutが起動される(本体は
Illuminate\Foundation\Auth\AuthenticatesUsersにある)

このままじゃredirectされないのでaxios.post(/logout).then(location="/")でredirectしてあげる。

ExampleComponent.vue
<template>
  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-8">
        <div class="card">
          <div class="card-header">Example Component</div>

          <div class="card-body">
            I'm an example component.
            <button @click="laraLogout">logout</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  mounted() {
    console.log("Component mounted.");
  },
  methods: {
    laraLogout() {
      axios
        .post("/logout")
        .then(response => {
          location = "/";
        })
        .catch(error => {
          console.log(error);
        });
    }
  }
};
</script>

##2-2 ほんのちょっとだけlaravel延長戦
vueでpermissionを使うために少しだけlaravel側をいじっておきます。

user.phpにアクセサーを追加します。

user.php
  public function getAllPermissionsAttribute()
    {
        $permissions = [];
        foreach (Permission::all() as $permission) {
            if (auth()->user()->can($permission->name)) {
                //もし今ログインしているユーザーがこのpermissionを持っていれば
                $permissions[] = $permission->name;
            }
        }

        //今ログインしているユーザーの持っているpermissionを返してあげる
        return $permissions;
    }

↑で作った$permissionsを、home.blade.phpで受け取ってVue上でGlobalに使えるようにします。

home.blade.php
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link rel="stylesheet" href="{{asset('css/app.css')}}">
    <title>test</title>
    {{-- ここに追加!! --}}
    <script>
     @auth
      window.Permissions = @json(auth()->user()->allPermissions);
     @else
      window.Permissions = [];
     @endauth
    </script>
     {{-- ここに追加!! --}}
</head>

今ログインしているユーザーがPermissionを持っているか判定する関数をGlobalに作ります。
(Mixinを使うんですが、あまりMixinはよくないとの意見もあるみたいなのでpluginにするかもしれません。)

resources/js/mixins/Permissions.jsを作ります。
laravel-permissionQiitaScreen1.PNG

Permissions.jsの中身は写真と同じようにしてください。

resources/js/app.jsでPermissionsをmixin

app.js
 import permissions from "./mixins/Permissions.js";
 Vue.mixin(permissions);

あとは使いたい場所で$can(判定したいpermission)を使います。試しに書いてみましょう。

ExampleComponent.vue
 <div class="card-body">
            I'm an example component.
            <button @click="laraLogout">logout</button>
          </div>
         <!-- ここに追加! -->
          <div v-if="$can('read_allusers')">readallUsers</div>
          <div v-if="$can('read_hiddenpage')">readhiddenPage</div>

成功していればこのようになっていると思います。
laravelpermissionGif1.gif

2-3 vue-routerを使おう!

  npm install vue-routerをします。
 router.jsを作る前に少し以前のファイルに変更するのと、2つComponentを作りたいのでそこから。
 
まずはhome.blade.phpから。

home.blade.php
 <body>
    <div id="app">
    {{-- ここを変更 --}}
    <router-view></router-view>
    </div>
    <script src="{{asset('js/app.js')}}">
    </script>

</body>

ExampleComponent

ExampleComponent.vue
 <div class="card-body">
            I'm an example component.
            <button @click="laraLogout">logout</button>
          </div>
          <!-- ここに追加! -->
          <div>
            <router-link to="/allusers">read_allUsers</router-link>
          </div>
          <div>
            <router-link to="/hiddenpage">read_hiddenPage</router-link>
          </div>

2つComponentを作ります。
AllUsers

AllUsers.vue
 <template>
  <div>
    <div>allUsers</div>
    <div v-if="$can('delete_user')">can delete User</div>
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>

HiddenPage

HiddenPage.vue
 <template>
  <div>This is Hidden Page</div>
</template>

<script>
export default {};
</script>

<style>
</style>

以上です。お疲れさまでした。

変更も終わったので、js/router/router.jsを作ります。

laravel-permissionQiitaScreen2.PNG

router.js
import Vue from "vue";
import VueRouter from "vue-router";
import HiddenPage from "../components/HiddenPage.vue";
import AllUsers from "../components/AllUsers.vue";
import Example from "../components/ExampleComponent.vue";

Vue.use(VueRouter);
const $can = permissionName => {
    return Permissions.indexOf(permissionName) !== -1;
};

const routes = [
    {
        path: "/hiddenpage",
        component: HiddenPage,
        beforeEnter(to, from, next) {
            if ($can("read_hiddenpage")) {
                next();
            } else {
                //errorPageに飛ばしたい場合はエラーページを作って、ここのnextに入れてあげればいい
                alert("403 forbidden");
            }
        }
    },
    {
        path: "/allusers",
        component: AllUsers
    },
    {
        path: "/home",
        component: Example
    }
];

const router = new VueRouter({
    routes,
    hashbang: false,
    mode: "history"
});

export default router;

あとはapp.jsにrouter.jsを登録するだけです。

app.js
 //////

 import router from "./router/router";

 //////
 const app = new Vue({
    el: "#app",
    router
});

ここまでで以下のような動きになっていると思います。長々とありがとうございました。
laravelpermissionGif2.gif

# おわりに
どこまで端折っていいかの区別ができていなくて無駄に長くなってしまった感じがします。
課題としてlaravelのmiddlewareによるguardとvue-routerのguardをどう組み合わせていけばいいかがわからないままでした。
組み合わせなくてもどちらか一方でいいんですかね・・・?
どなたかアドバイスをいただければものすごく助かります。

 
 
 

# 参考
##laravel-permissionについて

 
 

Vueについて

 

11
9
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
11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?