<strong>3.</strong> İzin Göçünü Değiştirin<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:migration create_permission_alter_table 

<p>Göç dosyasını güncelleyin: database/migrations/xxxx_xx_xx_xxxx_create_permission_alter_table.php<br/></p>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>

<?php use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table(‘permissions’, function (Blueprint $table) {
$table-?>unsignedBigInteger(‘module_id’)->after(‘id’);
$table->unsignedBigInteger(‘component_id’)->after(‘module_id’);
$table->string(‘label’)->after(‘component_id’);
});
}

public function down(): void
{
    Schema::table('permissions', function (Blueprint $table) {
        $table-&gt;dropColumn('module_id');
        $table-&gt;dropColumn('component_id');
        $table-&gt;dropColumn('label');
    });
}

};

<strong>4.</strong> Modül, Bileşen ve İzinler için Modeller Oluşturun<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:model Module

php artisan make:model ModuleComponent
php artisan make:model ModuleHasPermission

<strong>5.</strong> Seeder Oluşturun<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:seeder DatabaseSeeder

<p>Aşağıdaki fonksiyonu database/seeders/DatabaseSeeder.php'ye kopyalayın ve yapıştırın:<br/></p>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><?php namespace Database\Seeders;

use App\Models\User;
use App\Models\Modules\Module;
use App\Models\Modules\ModuleComponent;
use App\Models\Modules\Permission;
use App\Models\Modules\ModuleHasPermission;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Seeder;

class DatabaseNewSeeder extends Seeder
{
public function run(): void
{
$user = User::factory()-?>create([
‘name’ => ‘Test Admin’,
’email’ => ‘[email protected]’,
‘password’ => Hash::make(‘12345678’),
]);

    $adminRole = Role::firstOrCreate(['name' =&gt; 'admin']);
    $userRole  = Role::firstOrCreate(['name' =&gt; 'user']);
    $user-&gt;syncRoles([$adminRole-&gt;name]);

    $modules = [
        'Users' =&gt; ['Details', 'Permissions'],
        'Tasks' =&gt; ['List'],
        'Settings' =&gt; ['Details']
    ];

    foreach ($modules as $moduleName =&gt; $components) {
        $module = Module::create([
            'name' =&gt; $moduleName,
            'slug' =&gt; strtolower($moduleName),
        ]);

        foreach ($components as $componentName) {
            $component = ModuleComponent::create([
                'module_id' =&gt; $module-&gt;id,
                'name' =&gt; $componentName,
                'slug' =&gt; strtolower($componentName),
            ]);

            $crudLabels = ['View', 'Add', 'Edit', 'Delete'];
            foreach ($crudLabels as $label) {
                $permissionName = strtolower($moduleName) . '.' . strtolower($componentName) . '.' . strtolower($label);
                $permission = Permission::create([
                    'module_id' =&gt; $module-&gt;id,
                    'component_id' =&gt; $component-&gt;id,
                    'label' =&gt; $label,
                    'name' =&gt; $permissionName,
                    'guard_name' =&gt; 'web',
                ]);

                ModuleHasPermission::create([
                    'permission_id' =&gt; $permission-&gt;id,
                    'model_id' =&gt; $user-&gt;id,
                    'model_type' =&gt; User::class,
                ]);
            }
        }
    }
}

}

<strong>Seeder'ı çalıştırın:</strong><br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan db:seed --class=DatabaseSeeder

<strong>Adım 5: Auth API Oluşturun</strong><br/><strong>1.</strong> AuthController Oluşturun<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:controller AuthController

<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><?php namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
public function login(Request $request)
{
$request-?>validate([
’email’=>’required|email’,
‘password’=>’required’
]);

    $user = User::where('email', $request-&gt;email)-&gt;first();

    if (!$user || !Hash::check($request-&gt;password, $user-&gt;password)) {
        throw ValidationException::withMessages([
            'email' =&gt; ['Invalid credentials.']
        ]);
    }

    $token = $user-&gt;createToken('api-token')-&gt;plainTextToken;

    return response()-&gt;json([
        'user'=&gt;$user,
        'token'=&gt;$token
    ]);
}

public function show_permissions()
{
    $auth = Auth::user(); 
    $admin['detail'] = $auth;
    $admin['roles'] = $auth-&gt;getRoleNames();
    $admin['permissions'] = $auth-&gt;getPermissionNames();
    return response()-&gt;json($admin, '201');
}

public function logout(Request $request)
{
    $request-&gt;user()-&gt;currentAccessToken()-&gt;delete();
    return response()-&gt;json(['message'=&gt;'Logged out']);
}

}

<strong>2.</strong> UserController Oluşturun<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:controller UserController

<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><?php namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\Request;

class UserController extends Controller
{
public function index()
{
$users = User::get();
return response()-?>json($users, 200);
}

public function store(Request $request)
{
    $request-&gt;validate([
        'role'=&gt;'required',
        'name'=&gt;'required',
        'email'=&gt;'required|email|unique:users',
        'password'=&gt;'required|min:6'
    ]);

    $user = User::create([
        'name'=&gt;$request-&gt;name,
        'email'=&gt;$request-&gt;email,
        'password'=&gt;Hash::make($request-&gt;password),
    ]);

    $user-&gt;assignRole($request-&gt;role); 

    return response()-&gt;json($user, 201);
}

public function update(int $id, Request $request)
{
    $user = User::findOrFail($id);
    $request-&gt;validate([
        'role' =&gt; 'required|string', 
        'name'  =&gt; 'required|string|max:255',
        'email' =&gt; [
            'required',
            'email',
            Rule::unique('users')-&gt;ignore($user-&gt;id),
        ],
    ]);

    $user-&gt;update([
        'name'  =&gt; $request-&gt;name,
        'email' =&gt; $request-&gt;email,
    ]);

    $user-&gt;syncRoles([$request-&gt;role]);
    return response()-&gt;json($user, 201);
}

public function show(int $id)
{
    $user = User::findOrFail($id); 
    $user-&gt;role = $user-&gt;getRoleNames();
    return response()-&gt;json($user, 201);
}

public function destroy(int $id)
{
    $user = User::findOrFail($id);
    $delete =  $user-&gt;delete();
    return response()-&gt;json($delete, 201);
}

}

<strong>3.</strong> ModuleController Oluşturun<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan make:controller ModuleController

<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><?php namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Modules\Module;
use App\Models\Modules\ModuleComponent;
use App\Models\Modules\Permission;
use App\Models\Modules\ModuleHasPermission;

class ModuleController extends Controller
{
public function index()
{
$modules = Module::get();
foreach($modules as $key =?> $row){
$data[‘module_id’] = $row->id;
$data[‘module_name’] = $row->label;
$permissions = Permission::where(‘module_id’, $row->id)->get();
$data[‘module_permissions’] = $permissions;
}
return response()->json($module, 201);
}

public function permission(int $user)
{
    $actions = array('View', 'Add', 'Edit', 'Delete');
    $modules = Module::get();
    foreach($modules as $key =&gt; $row){
        $data[$key]['module_id'] = $row-&gt;id;
        $data[$key]['module_name'] = $row-&gt;name;

        $components = ModuleComponent::where('module_id', $row-&gt;id)-&gt;get();
        $component = array();
        foreach($components as $i =&gt; $comp){
            $component[$i]['component_label'] = $comp-&gt;name;
            $action_arry = [];
            foreach($actions as $j =&gt; $action){
                $permission = Permission::where('module_id', $row-&gt;id)-&gt;where('component_id', $comp-&gt;id)-&gt;where('label', $action)-&gt;first();
                $per = array();
                if(isset($permission-&gt;id)){
                    $per['per_id'] = $permission-&gt;id;
                    $per['per_label'] = $permission-&gt;label;
                    $per['per_name'] = $permission-&gt;name;
                    $admin_per = ModuleHasPermission::where('model_id', $user)-&gt;where('permission_id', $permission-&gt;id)-&gt;first();
                    if(isset($admin_per-&gt;model_id)){
                        $per['check'] = 1;
                    }else{
                        $per['check'] = 0;
                    }
                }
                $action_arry[$j] = $per;
            }
            $component[$i]['component_actions'] = $action_arry;
        }
        $data[$key]['module_permissions'] = $component;
    }             
    return response()-&gt;json($data, 201);
}  

public function store(int $user, Request $request)
{
    $modules = $request-&gt;all();
    foreach($modules as $key =&gt; $row){
        foreach($row['module_permissions'] as $i =&gt; $comp){
            foreach($comp['component_actions'] as $ind =&gt; $val){
                if(isset($val['check']) &amp;&amp; $val['check'] == 1){
                    $admin_per = ModuleHasPermission::where('model_id', $user)-&gt;where('permission_id', $val['per_id'])-&gt;first();
                    if(empty($admin_per)){
                        $per_create = ModuleHasPermission::create([
                            'model_id' =&gt; $user,
                            'permission_id' =&gt; $val['per_id'],
                            'model_type' =&gt; 'App\Models\User',
                        ]);
                    }
                }
                if(isset($val['check']) &amp;&amp; $val['check'] == 0){
                    $admin_per = ModuleHasPermission::where('model_id', $user)-&gt;where('permission_id', $val['per_id'])-&gt;first();
                    if(isset($admin_per-&gt;model_id)){
                        $per_delete = ModuleHasPermission::where('model_id', $user)-&gt;where('permission_id', $val['per_id'])-&gt;delete();
                    }
                }
            }
        }
    } 

    return response()-&gt;json($modules, 201);
}  

}

<strong>4.</strong> Routes'u ekleyin routes/api.php:<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><?php use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\UserController;
use App\Http\Controllers\ModuleController;

Route::post(‘/register’, [AuthController::class, ‘register’]);
Route::post(‘/login’, [AuthController::class, ‘login’]);

Route::middleware(‘auth:sanctum’)-?>group(function () {
Route::post(‘/logout’, [AuthController::class, ‘logout’]);
Route::get(“/users-permissions”, [AuthController::class, “show_permissions”]);
Route::apiResource(“/users”, UserController::class);
Route::get(“/users/{user}/permissions”, [ModuleController::class, “permission”]);
Route::post(“/users/{user}/permissions”, [ModuleController::class, “store”]);
});

<hr/>

<strong>Adım 6: Vue 3 Ön Yüzünü Kurun</strong><br/>
<strong>1.</strong> Bir Vue 3 projesi oluşturun (aynı veya başka bir klasöre):<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>npm create vite@latest frontend

cd frontend
npm install
npm install axios pinia vue-router

<strong>2.</strong> Axios API Global Konfigürasyonu<br/>src/stores/api.js<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>import axios from 'axios';

axios.defaults.baseURL = ‘http://127.0.0.1:8000/api‘;
axios.defaults.headers.common[‘Accept’] = ‘application/json’;

const token = localStorage.getItem(‘token’);
if (token) {
axios.defaults.headers.common[‘Authorization’] = Bearer ${token};
}

export default axios;

<strong>3.</strong> Pinia Store'u Kurun<br/>src/stores/auth.js<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>import { defineStore } from 'pinia';

import axios from ‘axios’;
import api from ‘./api’;

const api_url=”http://127.0.0.1:8000“;

export const useAuthStore = defineStore(‘auth’, {
state: () => ({
user: null,
token: localStorage.getItem(‘token’) || null,
}),

getters: {
isLoggedIn: (state) => !!state.token,
},

actions: {
async login(credentials) {
axios.get(api_url+’/sanctum/csrf-cookie’)
const res = await axios.post(api_url+’/api/login’, credentials);

    this.user = res.data.user;
    this.token = res.data.token;

    localStorage.setItem('token', this.token);
    axios.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
},
async logout() {
  await api.post('/logout');

  this.user = null;
  this.token = null;

  localStorage.removeItem('token');
  delete axios.defaults.headers.common['Authorization'];
},

},
});

<strong>src/stores/permission.js<br/></strong>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>import { defineStore } from 'pinia'

import api from ‘./api’;

export const usePermissionStore = defineStore(‘permission’, {
state: () => ({
user: null,
roles: [],
permissions: [],
loaded: false,
}),
actions: {
async fetchUser() {
await api.get(/users-permissions)
.then((resp) => {
this.user = resp.data.detail
this.roles = resp.data.roles
this.permissions = resp.data.permissions
this.loaded = true
})
},
can(check_permission) {
return this.permissions.includes(check_permission)
},
canRole(check_role) {
return this.roles.includes(check_role)
}
}
})

<strong>4.</strong> Vue Router ile Auth Guard<br/>src/router/index.js<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>import { createRouter, createWebHistory } from 'vue-router';

import { useAuthStore } from ‘../stores/auth’;
import { usePermissionStore } from ‘../stores/permission’
import Login from ‘../views/Login.vue’;
import Dashboard from ‘../views/Dashboard.vue’;
import Task from ‘../views/Task.vue’;

const routes = [
{ path: ‘/login’, component: Login },
{
path: ‘/dashboard’,
component: Dashboard,
meta: {
requiresAuth: true,
},
},
{
path: ‘/tasks’,
component: Task,
meta: {
requiresAuth: true,
permission: [‘tasks.list.view’]
},
},
{ path: “https://dev.to/“, redirect: ‘/dashboard’ },
];

const router = createRouter({
history: createWebHistory(),
routes,
});

router.beforeEach(async (to, from, next) => {
const auth = useAuthStore();
const adminStore = usePermissionStore()

if (!adminStore.loaded && auth.isLoggedIn) {
await adminStore.fetchUser()
}

if (to.matched.some(record => record.meta.requiresAuth)) {
if (!auth.isLoggedIn) {
next({
path: ‘/login’,
query: { redirect: to.fullPath }
});
} else {
const requiredRoles = to.meta.role
const requiredPermissions = to.meta.permission
if (requiredRoles && !requiredRoles.some(r => adminStore.canRole(r))) {
next({ path: ‘/unauthorized’ })
}
else if (requiredPermissions && !requiredPermissions.some(p => adminStore.can(p))) {
next({ path: ‘/unauthorized’ })
} else {
next()
}
}
} else if (to.matched.some(record => record.meta.guestOnly)) {
if (auth.isLoggedIn) {
next({ path: “https://dev.to/” })
} else {
next()
}
} else {
next()
}
})

export default router;

<strong>5.</strong> main.js'i değiştirin<br/>src/main.js<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>import { createApp } from 'vue'

import { createPinia } from ‘pinia’;
import router from ‘./router’;
import ‘./style.css’
import App from ‘./App.vue’

createApp(App)
.use(createPinia())
.use(router)
.mount(‘#app’);

<ol>
    <li>Login Ekranı</li>
</ol>

<p>src/views/Login.vue<br/></p>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>


<strong>7.</strong> Dashboard Ekranı<br/>src/Dashboard.vue<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><template>

Roles: {{ permissionStore.user?.roles[0]?.name }}

<div class="bg-white p-8 rounded-xl shadow mb-5" v-if="permissionStore.can('settings.details.view')">
  <p>This is settings section.</p>
</div>
<p>
  <router-link to="/tasks" class="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700" v-if="permissionStore.can('tasks.list.view')">
    View Tasks
  </router-link>
</p>

<button class="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700">Logout</button>

<strong>8.</strong> Görev Ekranı<br/>src/Task.vue<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code><template>

<div class="bg-white shadow rounded-lg overflow-hidden">
  <table class="w-full">
    <thead class="bg-gray-800 text-white">
      <tr>
        <th class="px-4 py-3 text-left">Title</th>
        <th class="px-4 py-3 text-left">Action Date</th>
        <th class="px-4 py-3 text-left">Due Date</th>
        <th class="px-4 py-3 text-left">Status</th>
        <th class="px-4 py-3 text-left">Actions</th>
      </tr>
    </thead>

    <tbody>
      <tr v-for="task in tasks" :key="task.id" class="border-t border-t-gray-300 hover:bg-gray-50">
        <td class="px-4 py-3">{{ task.title }}</td>
        <td class="px-4 py-3">{{ task.action_date }}</td>
        <td class="px-4 py-3">{{ task.due_date }}</td>
        <td class="px-4 py-3">{{ task.status }}</td>
        <td class="px-4 py-3 space-x-2">
         <button type="button" v-if="permissionStore.can('tasks.list.edit')" class="text-indigo-600 hover:underline">Edit</button>
            <button type="button" v-if="permissionStore.can('tasks.list.delete')" class="text-indigo-600 hover:underline">Delete</button>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<strong>Adım 7: Her Şeyi Test Edin</strong><br/>Laravel API'yi çalıştırın:<br/>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>php artisan serve

<p>Vue 3 ön yüzünü çalıştırın:<br/></p>
<div class="highlight js-code-highlight">
    <pre class="highlight plaintext"><code>npm run dev

<p><strong>GitHub:</strong><br/>Laravel 12, Vue 3 ve Tailwind CSS ile oluşturulmuş CMS İzin Sistemi'ni GitHub'da kontrol edin: <br/><a href="https://github.com/malickfaisal/cms-permission-vue-laravel" target="_blank" rel="noopener noreferrer">https://github.com/malickfaisal/cms-permission-vue-laravel</a><br/>Kodları keşfedin, deneyin ve rol tabanlı &amp; modül tabanlı izinlerin nasıl çalıştığını görün!</p>

Kaynak: Orijinal Makale

Bu Makaleyi Paylaş