# はじめに
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 installとnpm run devをやってください。
1-3 laravel-permissionのインストール
composer require spatie/laravel-permission
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トレイトを追加しておきましょう。
class User extends Authenticatable
{
use Notifiable;
use HasRoles;//これを追加!
}
1-4 seedingによりRoleとPermissionを設定する
roleはadmin、userの二つ、
permissionはread_hiddenpage、read_allusers、delete_userの三つとします。
role | permission |
---|---|
user | read_allusers |
admin | read_allusers,delete_user,read_hiddenpage |
という風にしていきます。 |
まずroleTableからseeding
<?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
<?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
<?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
<?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してあげる。
<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にアクセサーを追加します。
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に使えるようにします。
<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を作ります。
Permissions.jsの中身は写真と同じようにしてください。
resources/js/app.jsでPermissionsをmixin
import permissions from "./mixins/Permissions.js";
Vue.mixin(permissions);
あとは使いたい場所で$can(判定したいpermission)を使います。試しに書いてみましょう。
<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>
2-3 vue-routerを使おう!
npm install vue-router
をします。
router.jsを作る前に少し以前のファイルに変更するのと、2つComponentを作りたいのでそこから。
まずはhome.blade.phpから。
<body>
<div id="app">
{{-- ここを変更! --}}
<router-view></router-view>
</div>
<script src="{{asset('js/app.js')}}">
</script>
</body>
ExampleComponent
<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
<template>
<div>
<div>allUsers</div>
<div v-if="$can('delete_user')">can delete User</div>
</div>
</template>
<script>
export default {};
</script>
<style>
</style>
HiddenPage
<template>
<div>This is Hidden Page</div>
</template>
<script>
export default {};
</script>
<style>
</style>
以上です。お疲れさまでした。
変更も終わったので、js/router/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を登録するだけです。
//////
import router from "./router/router";
//////
const app = new Vue({
el: "#app",
router
});
ここまでで以下のような動きになっていると思います。長々とありがとうございました。
# おわりに
どこまで端折っていいかの区別ができていなくて無駄に長くなってしまった感じがします。
課題としてlaravelのmiddlewareによるguardとvue-routerのguardをどう組み合わせていけばいいかがわからないままでした。
組み合わせなくてもどちらか一方でいいんですかね・・・?
どなたかアドバイスをいただければものすごく助かります。
# 参考
##laravel-permissionについて
- laravel-permissionの使い方
- laravel-permissionを試す
- Laravelでユーザーごとの権限を管理するlaravel-permissionをインストールする
- Create an Admin middleware for Laravel with spatie/laravel-permission
Vueについて