Muzibu.com Multi-Tenant SaaS Platformu - Kapsamlı Yetkilendirme Analizi
Sistem, kullanıcıları üç ana gruba ayırır: root (süper yönetici), admin (yönetici) ve editor (editör). Her grubun farklı yetkileri vardır.
Her şeyi yapabilir. Sistemin her yerine erişebilir, tüm ayarları değiştirebilir. Hem merkezi sistemde (central) hem de her müşterinin (tenant) kendi alanında tam yetkilidir.
Kendi alanında tam yetkili. Bir müşterinin (tenant) kendi sisteminde her şeyi yönetebilir, ancak sadece kendisine atanan modülleri kullanabilir. Central sistemde bazı kısıtlamaları vardır.
Sınırlı yetkiler. Sadece kendisine özel olarak verilen modülleri ve belirli işlemleri (görüntüleme, ekleme, düzenleme, silme) yapabilir. Her modül için ayrı ayrı izin verilir.
Bu sistem sayesinde her kullanıcı sadece yapması gereken işleri görebilir. Bir editörün yanlışlıkla önemli ayarları bozması veya başka kullanıcıların verilerine erişmesi engellenir. Güvenlik ve düzen sağlanır.
📁 Modules/UserManagement/App/Models/Role.php
class Role extends SpatieRole {
const BASE_ROLES = ['root', 'admin', 'editor'];
const ROLE_TYPES = [
'root' => 'Tam Yetkili Yönetici',
'admin' => 'Yönetici',
'editor' => 'Editör'
];
protected $fillable = ['name', 'guard_name', 'is_protected', 'role_type', 'description'];
public function isRoot(): bool { return $this->role_type === 'root'; }
public function isAdmin(): bool { return $this->role_type === 'admin'; }
public function isEditor(): bool { return $this->role_type === 'editor'; }
public function isDeletable(): bool {
return !$this->isBaseRole() && !$this->is_protected && $this->users()->count() === 0;
}
}
📁 app/Models/User.php
use Spatie\Permission\Traits\HasRoles;
use Modules\UserManagement\App\Traits\HasModulePermissions;
class User extends Authenticatable {
use HasRoles, HasModulePermissions;
protected $guard_name = 'web';
// Spatie Permission override (global scope bypass)
public function roles() {
return $this->morphToMany(Role::class, 'model', 'model_has_roles')
->where('roles.guard_name', 'web')
->withoutGlobalScopes(); // 🔴 KRİTİK: Multi-tenant için
}
// Cache-aware rol kontrolü
public function hasCachedRole($role): bool {
return cache()->remember("user_role_{$this->id}_{$role}", 300, fn() => $this->hasRole($role));
}
// Rol helper metodları
public function isRoot(): bool { return $this->hasRole('root'); }
public function isAdmin(): bool { return $this->hasRole('admin'); }
public function isEditor(): bool { return $this->hasRole('editor'); }
}
📊 roles tablosu (Central + Tenant) ┌───────────────┬──────────────┬─────────────┐ │ Kolon │ Tip │ Açıklama │ ├───────────────┼──────────────┼─────────────┤ │ id │ bigint │ PK │ │ name │ varchar(255) │ root/admin │ │ guard_name │ varchar(255) │ web │ │ role_type │ varchar(50) │ rol tipi │ │ is_protected │ boolean │ silinemez │ │ description │ text │ açıklama │ └───────────────┴──────────────┴─────────────┘ 📊 model_has_roles tablosu (Spatie) ┌───────────────┬──────────────┬─────────────┐ │ role_id │ bigint │ FK roles │ │ model_type │ varchar(255) │ App\Models\User │ │ model_id │ bigint │ user_id │ └───────────────┴──────────────┴─────────────┘
📁 database/seeders/RolePermissionSeeder.php
// Root kullanıcıları (her tenant + central)
$rootEmails = ['nurullah@nurullah.net', 'info@turkbilisim.com.tr'];
// Central DB
if (isCentral()) {
createOrUpdateRole('root', 'Tam yetkili sistem yöneticisi', 'root', true);
createOrUpdateRole('admin', 'Tenant yöneticisi', 'admin', true);
createOrUpdateRole('editor', 'Modül bazlı yetkilendirilebilir editör', 'editor', true);
}
// Tenant DB
if (isTenant()) {
// Aynı roller tenant DB'ye de eklenir
Role::create(['name' => 'root', 'role_type' => 'root', 'is_protected' => true]);
}
Sistem, modüler bir yapıya sahip. Yani her özellik (blog, müzik, ödeme sistemi gibi) birer modüldür. Her modül için 4 farklı işlem izni vardır:
Modülün içeriğini görebilir, listeleyebilir
Yeni kayıt ekleyebilir (yeni şarkı, blog yazısı)
Mevcut kayıtları düzenleyebilir
Kayıtları silebilir
Ali adında bir editör var. Ali'ye Blog modülü için şu izinler verilmiş:
Aynı zamanda Ali'ye Müzik modülü için sadece VIEW izni verilmiş. Yani şarkıları görebilir ama ekleyemez, düzenleyemez veya silemez.
Bu sistem sayesinde her editörün yetkisi tam olarak kontrol edilir. Bir kişinin yanlışlıkla önemli verileri silmesi veya yetkisi olmayan alanlara erişmesi engellenir. Her kişi sadece yapması gereken işleri yapar.
📁 Modules/UserManagement/App/Traits/HasModulePermissions.php
trait HasModulePermissions {
// Ana yetki kontrolü
public function hasModulePermission(string $moduleName, string $permissionType): bool {
// 1. Root: Her zaman true
if ($this->hasRole('root')) return true;
// 2. Admin: Tenant'a atanmış modüller için true
if ($this->hasRole('admin')) {
if (tenant()) {
$module = ModuleAccessService::getModuleByName($moduleName);
return ModuleAccessService::isModuleAssignedToTenant($module->module_id, tenant()->id);
}
// Central'da kısıtlı modüller kontrol edilir
return !in_array($moduleName, config('module-permissions.admin_restricted_modules'));
}
// 3. Editor: UserModulePermission tablosundan kontrol
$cacheKey = "user_{$this->id}_module_{$moduleName}_permission_{$permissionType}";
return Cache::remember($cacheKey, 300, function() {
return $this->userModulePermissions()
->where('module_name', $moduleName)
->where('permission_type', $permissionType)
->where('is_active', true)
->exists();
});
}
// Modülün tüm izinlerini getir
public function getModulePermissions(string $moduleName): array {
if ($this->isRoot() || $this->isAdmin()) {
return ['view', 'create', 'update', 'delete'];
}
return $this->userModulePermissions()
->where('module_name', $moduleName)
->where('is_active', true)
->pluck('permission_type')
->toArray();
}
// İzin ekleme
public function giveModulePermissionTo(string $moduleName, $permissionTypes): void {
foreach ((array)$permissionTypes as $type) {
UserModulePermission::updateOrCreate(
['user_id' => $this->id, 'module_name' => $moduleName, 'permission_type' => $type],
['is_active' => true]
);
}
$this->clearModulePermissionCache($moduleName);
}
}
📁 Modules/UserManagement/App/Models/UserModulePermission.php
class UserModulePermission extends Model {
protected $fillable = ['user_id', 'module_name', 'permission_type', 'is_active'];
protected $casts = ['is_active' => 'boolean'];
public function user(): BelongsTo {
return $this->belongsTo(User::class);
}
public static function getPermissionTypes(): array {
return ModulePermission::getPermissionTypes();
}
}
📊 user_module_permissions tablosu
┌──────────────────┬──────────────┬────────────────────────────┐
│ Kolon │ Tip │ Açıklama │
├──────────────────┼──────────────┼────────────────────────────┤
│ id │ bigint │ PK │
│ user_id │ bigint │ FK users │
│ module_name │ varchar(50) │ 'blog', 'muzibu', vb. │
│ permission_type │ varchar(20) │ 'view', 'create', vb. │
│ is_active │ boolean │ aktif/pasif │
│ created_at │ timestamp │ │
│ updated_at │ timestamp │ │
├──────────────────┴──────────────┴────────────────────────────┤
│ UNIQUE: (user_id, module_name, permission_type) │
│ INDEX: module_name, permission_type, is_active │
└───────────────────────────────────────────────────────────────┘
📁 app/Helpers/ModulePermissionHelper.php
// Blade'de kullanım: @if(can_module('blog', 'create'))
function can_module(string $moduleName, string $permissionType = 'view'): bool {
$user = Auth::user();
if (!$user) return false;
if ($user->hasRole('root') || $user->hasRole('admin')) {
return true;
}
$cacheKey = "user_{$user->id}_module_{$moduleName}_permission_{$permissionType}";
return Cache::remember($cacheKey, 86400, fn() =>
$user->hasModulePermission($moduleName, $permissionType)
);
}
// Modül aktif mi kontrolü
function is_module_active(string $moduleName, string $permissionType = 'view'): bool {
$cacheKey = "module_{$moduleName}_permission_{$permissionType}_active";
return Cache::remember($cacheKey, 86400, function() use ($moduleName, $permissionType) {
return Module::where('name', $moduleName)
->where('is_active', true)
->whereHas('permissions', fn($q) =>
$q->where('permission_type', $permissionType)->where('is_active', true)
)
->exists();
});
}
Middleware, bir sayfa açılmadan önce çalışan güvenlik kontrol noktalarıdır. Tıpkı bir binanın güvenlik görevlisi gibi, her ziyaretçiyi kontrol eder ve yetkisi yoksa içeri almaz.
Bazı sayfalar sadece root kullanıcıların erişebileceği kadar kritiktir. Bu middleware, root olmayan hiç kimsenin o sayfalara girmesine izin vermez.
Admin paneline giriş yapmak isteyen herkesi kontrol eder. Root ve admin'lere izin verir, editörler için özel kontroller yapar. Ayrıca hangi modüle erişmeye çalıştığını tespit eder.
Debugbar (geliştirici debug araçları), sadece root kullanıcıların görebileceği hassas bilgiler içerir. Bu middleware, debugbar'ı sadece root kullanıcılara gösterir.
Middleware sistemi sayesinde her sayfa açılmadan önce yetki kontrolü yapılır. Yanlışlıkla veya kasıtlı olarak yetkisiz sayfalara erişim denemeleri engellenir. Sistem güvenliği otomatik olarak sağlanır, her sayfada ayrı kontrol yazmaya gerek kalmaz.
📁 app/Http/Middleware/RootAccessMiddleware.php
class RootAccessMiddleware {
public function handle(Request $request, Closure $next) {
// Root yetkisi kontrolü
if (!auth()->user() || !auth()->user()->isRoot()) {
abort(403, 'ERİŞİM ENGELENDİ.');
}
// Tenant kontrolü - sadece central'da erişime izin ver
if (TenantHelpers::isTenant()) {
abort(403, 'ERİŞİM ENGELENDİ.');
}
return $next($request);
}
}
📋 Kullanım:
Route::middleware(['auth', 'root'])->group(function() {
Route::get('/admin/system-settings', ...);
Route::get('/admin/create-tenant', ...);
});
📁 app/Http/Middleware/AdminAccessMiddleware.php
class AdminAccessMiddleware {
public function handle(Request $request, Closure $next) {
if (!auth()->check()) {
abort(403, 'Bu alana erişim yetkiniz bulunmamaktadır.');
}
$user = auth()->user();
// URL'den modül adını çıkar: /admin/blog/posts → 'blog'
preg_match('/^admin\/([^\/]+)/', $request->path(), $matches);
$moduleName = $matches[1] ?? null;
// Path-to-module mapping
$pathModuleMap = ['orders' => 'cart', 'checkout' => 'cart'];
if ($moduleName && isset($pathModuleMap[$moduleName])) {
$moduleName = $pathModuleMap[$moduleName];
}
// ROOT: Her yere erişebilir
if ($user->isRoot()) {
return $next($request);
}
// ADMIN: Tenant'a atanan modüllere erişebilir
if ($user->isAdmin()) {
$systemRoutes = ['dashboard', 'cache', 'debug', 'ai', 'language'];
if (in_array($moduleName, $systemRoutes)) {
return $next($request);
}
// Central'da kısıtlı modül kontrolü
if (TenantHelpers::isCentral() &&
in_array($moduleName, config('module-permissions.admin_restricted_modules'))) {
abort(403, 'Bu modüle erişim yetkiniz bulunmamaktadır.');
}
// Tenant'ta modül atama kontrolü (10 dakika cache)
if (TenantHelpers::isTenant() && $moduleName) {
$cacheKey = "module_tenant_access:{$moduleName}:" . tenant()->id;
$hasAccess = Cache::remember($cacheKey, 600, function() use ($moduleName) {
$module = ModuleAccessService::getModuleByName($moduleName);
return $module && ModuleAccessService::isModuleAssignedToTenant($module->module_id, tenant()->id);
});
if (!$hasAccess) {
abort(403, 'Bu modül bu tenant\'a atanmamış.');
}
}
return $next($request);
}
// EDITOR: Modül bazlı izin kontrolü
if ($user->isEditor()) {
if ($moduleName && !ModuleAccessService::canAccess($moduleName, 'view')) {
abort(403, 'Bu modüle erişim yetkiniz bulunmamaktadır.');
}
return $next($request);
}
abort(403, 'Bu alana erişim yetkiniz bulunmamaktadır.');
}
}
📁 app/Http/Middleware/RootOnlyDebugbar.php
class RootOnlyDebugbar {
public function handle(Request $request, Closure $next): Response {
if (!class_exists(\Barryvdh\Debugbar\Facade::class)) {
return $next($request);
}
$showDebugbar = false;
if (auth()->check()) {
$userId = auth()->id();
$sessionKey = "is_root_user_{$userId}";
if (session()->has($sessionKey)) {
// Session'dan al (0 query)
$showDebugbar = session($sessionKey);
} else {
// İlk kez: Cache'den al, session'a kaydet
$isRoot = Cache::remember("user_is_root_{$userId}", 300, fn() =>
auth()->user()?->hasRole('root') ?? false
);
session([$sessionKey => $isRoot]);
$showDebugbar = $isRoot;
}
}
if (!$showDebugbar) {
\Barryvdh\Debugbar\Facade::disable();
}
return $next($request);
}
}
Sistem, multi-tenant (çok kiracılı) bir yapıya sahip. Yani her müşteri (tenant) kendi bağımsız veritabanına sahip. Bir müşterinin yöneticisi, sadece kendi müşterisinin verilerine erişebilir, başka müşterilerin verilerini göremez.
Tüm tenant'ları, modülleri ve global ayarları tutan merkezi veritabanı. Sadece root kullanıcılar buraya tam erişebilir.
Her müşterinin kendi veritabanı. Kullanıcılar, içerikler, siparişler gibi tenant'a özel tüm veriler burada saklanır.
3 farklı müşteri var: Tuufi.com (central), Ixtif.com ve Muzibu.com
Her tenant'a hangi modüllerin aktif olacağı central DB'den kontrol edilir. Örneğin Muzibu'ya "Müzik" modülü atanmış ama Ixtif'e atanmamış.
Multi-tenant yapı sayesinde her müşteri tamamen izole edilmiş ortamda çalışır. Bir müşterinin yöneticisi yanlışlıkla başka müşterinin verilerini göremez veya değiştiremez. Veri güvenliği ve gizlilik maksimum seviyede sağlanır.
📁 HasModulePermissions Trait - Tenant-Aware Permission Check
public function hasModulePermission(string $moduleName, string $permissionType): bool {
// Root: Her zaman bypass
if ($this->hasRole('root')) return true;
// Admin: Tenant context'e göre kontrol
if ($this->hasRole('admin')) {
// Tenant initialized mı?
if (app(\Stancl\Tenancy\Tenancy::class)->initialized) {
// Modül bu tenant'a atanmış mı? (Central DB sorgusu)
$moduleService = app(\App\Services\ModuleAccessService::class);
$module = $moduleService->getModuleByName($moduleName);
if (!$module) {
\Log::warning("Module not found: {$moduleName}");
return false;
}
return $moduleService->isModuleAssignedToTenant($module->module_id, tenant()->id);
}
// Central'da ise admin_restricted_modules kontrolü
if (in_array($moduleName, config('module-permissions.admin_restricted_modules', []))) {
\Log::warning("Admin tried to access restricted module: {$moduleName}");
return false;
}
return true;
}
// Editor: UserModulePermission kontrolü (Tenant DB)
return $this->userModulePermissions()
->where('module_name', $moduleName)
->where('permission_type', $permissionType)
->where('is_active', true)
->exists();
}
📁 app/Services/ModuleAccessService.php
public function isModuleAssignedToTenant(string $moduleId, string $tenantId): bool {
// Central tenant (ID: 1) tüm modüllere erişebilir
if ($tenantId === '1' || $tenantId === 1) {
return true;
}
// Cache kontrolü (10 dakika)
$cached = $this->cache->getTenantAssignmentCache($moduleId, $tenantId);
if ($cached !== null) return $cached;
// Database'den kontrol et (Central DB'den!)
$isAssigned = TenantHelpers::central(function () use ($moduleId, $tenantId) {
// module_tenants tablosunda aktif atama var mı?
$assigned = DB::table('module_tenants')
->where('module_id', $moduleId)
->where('tenant_id', $tenantId)
->where('is_active', true)
->exists();
if ($assigned) return true;
// Veya tenant central tenant mı?
return DB::table('tenants')
->where('id', $tenantId)
->where('central', true)
->where('is_active', true)
->exists();
});
// Cache'e kaydet
$this->cache->setTenantAssignmentCache($moduleId, $tenantId, $isAssigned);
return $isAssigned;
}
// Tenant'ın modüllerini getir
public function getTenantModules(int $tenantId): \Illuminate\Support\Collection {
return TenantHelpers::central(function () use ($tenantId) {
// Central tenant tüm modüllere erişir
if ($tenantId === 1) {
return Module::where('is_active', true)->get();
}
// Diğer tenant'lar için module_tenants tablosundan
return Module::select('modules.*')
->join('module_tenants', 'modules.module_id', '=', 'module_tenants.module_id')
->where('module_tenants.tenant_id', $tenantId)
->where('module_tenants.is_active', true)
->where('modules.is_active', true)
->get();
});
}
📊 Central DB - module_tenants tablosu ┌─────────────┬──────────┬──────────────────────────────┐ │ Kolon │ Tip │ Açıklama │ ├─────────────┼──────────┼──────────────────────────────┤ │ id │ bigint │ PK │ │ module_id │ string │ FK modules (UUID) │ │ tenant_id │ bigint │ FK tenants │ │ is_active │ boolean │ aktif/pasif │ │ created_at │timestamp │ │ │ updated_at │timestamp │ │ └─────────────┴──────────┴──────────────────────────────┘ 📊 Tenant DB - user_module_permissions tablosu ┌──────────────────┬──────────────┬────────────────┐ │ user_id │ module_name │ permission_type│ ├──────────────────┼──────────────┼────────────────┤ │ 42 │ blog │ view │ │ 42 │ blog │ create │ │ 42 │ blog │ update │ │ 58 │ muzibu │ view │ └──────────────────┴──────────────┴────────────────┘ ⚠️ Bu tablo her tenant'ın kendi DB'sinde!
📁 app/Helpers/TenantHelpers.php
// Central DB'de sorgu çalıştırma
TenantHelpers::central(function () {
return Module::all(); // Central DB'den modülleri al
});
// Tenant kontrolü
if (TenantHelpers::isTenant()) {
// Tenant context'indeyiz
}
if (TenantHelpers::isCentral()) {
// Central domain'deyiz
}
Sistem, yetki kontrollerinde cache (önbellek) kullanır. Yani bir kullanıcının yetkisi bir kez kontrol edildiğinde, sonuç hatırlanır ve tekrar veritabanına sorulmaz. Bu sayede sistem çok daha hızlı çalışır.
Modül izin kontrolü cache süresi
Tenant-modül atama cache
Helper fonksiyon cache
Cache kullanmadan her sayfa yüklenişinde veritabanına 10-20 kez "bu kullanıcının yetkisi var mı?" diye sorulurdu. Cache sayesinde bu sorgu sayısı 0'a iner. Sayfa yükleme süreleri 10 kat hızlanır, veritabanı yükü azalır.
📁 Cache Key Yapısı
// Modül izin cache (5 dakika)
"user_{$userId}_module_{$moduleName}_permission_{$permissionType}"
Örnek: "user_42_module_blog_permission_create"
// Modülün tüm izinleri (60 dakika)
"user_{$userId}_module_{$moduleName}_permissions"
Örnek: "user_42_module_blog_permissions"
// Rol cache (5 dakika)
"user_role_{$userId}_{$roleName}"
"user_is_root_{$userId}"
// Tenant-modül atama (10 dakika)
"module_tenant_access:{$moduleName}:{$tenantId}"
// Modül aktif mi (24 saat)
"module_{$moduleName}_permission_{$permissionType}_active"
// Modül by name (15 dakika)
"module_by_name:{$moduleName}"
📁 HasModulePermissions Trait
public function hasModulePermission(string $moduleName, string $permissionType): bool {
if ($this->hasRole('root')) return true;
if ($this->hasRole('admin')) { /* ... */ }
// Editor için cache'li kontrol
$cacheKey = "user_{$this->id}_module_{$moduleName}_permission_{$permissionType}";
return Cache::remember($cacheKey, now()->addMinutes(5), function () use ($moduleName, $permissionType) {
// Spatie Permission kontrolü
$permissionName = "{$moduleName}.{$permissionType}";
if (!Permission::where('name', $permissionName)->exists()) {
\Log::error("Permission does not exist: {$permissionName}");
return false;
}
if ($this->hasPermissionTo($permissionName)) {
return true;
}
// Direct DB kontrolü (fallback)
$hasPermissionInDB = \DB::table('model_has_permissions')
->join('permissions', 'model_has_permissions.permission_id', '=', 'permissions.id')
->where('model_id', $this->id)
->where('model_type', get_class($this))
->where('permissions.name', $permissionName)
->exists();
if ($hasPermissionInDB) return true;
// UserModulePermission kontrolü
return $this->userModulePermissions()
->where('module_name', $moduleName)
->where('permission_type', $permissionType)
->where('is_active', true)
->exists();
});
}
📁 app/Services/ModuleAccessCache.php
class ModuleAccessCache {
const CACHE_TTL = 600; // 10 dakika
public function getAccessCache(int $userId, string $moduleName, string $permissionType): ?bool {
$key = $this->buildAccessKey($userId, $moduleName, $permissionType);
return Cache::get($key);
}
public function setAccessCache(int $userId, string $moduleName, string $permissionType, bool $hasAccess): void {
$key = $this->buildAccessKey($userId, $moduleName, $permissionType);
Cache::put($key, $hasAccess, self::CACHE_TTL);
}
public function getTenantAssignmentCache(string $moduleId, string $tenantId): ?bool {
$key = "module_tenant_assignment:{$moduleId}:{$tenantId}";
return Cache::get($key);
}
public function setTenantAssignmentCache(string $moduleId, string $tenantId, bool $isAssigned): void {
$key = "module_tenant_assignment:{$moduleId}:{$tenantId}";
Cache::put($key, $isAssigned, self::CACHE_TTL);
}
public function clearUserCache(string $userId): void {
// Wildcard cache clear (Redis pattern delete)
$pattern = "laravel_cache:user_{$userId}_*";
$keys = Redis::keys($pattern);
if ($keys) Redis::del($keys);
}
private function buildAccessKey(int $userId, string $moduleName, string $permissionType): string {
return "user_module_access:{$userId}:{$moduleName}:{$permissionType}";
}
}
📁 Cache Invalidation Points
// Rol değiştiğinde (User model)
public function flushRoleCache(): void {
app(\Spatie\Permission\PermissionRegistrar::class)->forgetCachedPermissions();
$this->unsetRelation('roles');
$this->unsetRelation('permissions');
\Cache::forget("user_{$this->id}_roles");
\Cache::forget("user_{$this->id}_permissions");
}
// Modül izni eklendiğinde/kaldırıldığında
private function clearModulePermissionCache(string $moduleName): void {
$permissionTypes = UserModulePermission::getPermissionTypes();
foreach ($permissionTypes as $type => $name) {
Cache::forget("user_{$this->id}_module_{$moduleName}_permission_{$type}");
}
Cache::forget("user_{$this->id}_module_{$moduleName}_permissions");
}
// Tüm modül cache'i temizleme
ModuleAccessService::clearModuleAccessCache($userId); // Belirli kullanıcı
ModuleAccessService::clearModuleAccessCache(); // Tüm cache
📁 RootOnlyDebugbar Middleware - Zero Query Optimization
if (auth()->check()) {
$userId = auth()->id();
$sessionKey = "is_root_user_{$userId}";
if (session()->has($sessionKey)) {
// Session'dan al (0 DB query, 0 Redis query)
$showDebugbar = session($sessionKey);
} else {
// İlk kez: Redis cache + session
$isRoot = Cache::remember("user_is_root_{$userId}", 300, fn() =>
auth()->user()?->hasRole('root') ?? false
);
session([$sessionKey => $isRoot]); // Session'a kaydet
$showDebugbar = $isRoot;
}
}
// Sonraki isteklerde: Session'dan okur, hiç sorgu yapmaz! ⚡
{{-- Root kontrolü --}}
@if(auth()->user()->isRoot())
<button class="btn btn-danger">Sistemi Sıfırla</button>
@endif
{{-- Modül izin kontrolü --}}
@if(can_module('blog', 'create'))
<a href="{{ route('admin.blog.create') }}">Yeni Yazı Ekle</a>
@endif
{{-- Çoklu izin kontrolü --}}
@if(auth()->user()->hasModulePermissions('muzibu', ['update', 'delete']))
<button class="btn btn-warning">Düzenle</button>
<button class="btn btn-danger">Sil</button>
@endif
{{-- Rol bazlı UI --}}
@role('admin')
<div class="admin-panel">Yönetici Paneli</div>
@endrole
@role('editor')
<div class="editor-panel">Editör Paneli</div>
@endrole
use App\Services\ModuleAccessService;
class BlogController extends Controller {
public function __construct(protected ModuleAccessService $moduleAccess) {
// Middleware ile genel kontrol
$this->middleware(['auth', 'admin']);
}
public function create() {
// İzin kontrolü
if (!$this->moduleAccess->canAccess('blog', 'create')) {
abort(403, 'Blog oluşturma yetkiniz yok.');
}
return view('blog.create');
}
public function destroy(Blog $blog) {
// Policy kullanımı
$this->authorize('delete', $blog);
// veya manuel kontrol
if (!auth()->user()->hasModulePermission('blog', 'delete')) {
abort(403);
}
$blog->delete();
return redirect()->back();
}
}
📁 app/Policies/WidgetPolicy.php
class WidgetPolicy {
// Root-only işlem
public function update(User $user, Widget $widget): bool {
return $user->hasRole('root');
}
// Modül bazlı izin
public function manageContent(User $user, Widget $widget): bool {
return $user->hasModulePermission('widgetmanagement', 'update');
}
// Karmaşık kontrol
public function delete(User $user, Widget $widget): bool {
if ($user->isRoot()) return true;
if ($user->isAdmin()) {
// Admin sadece kendi tenant'ının widget'larını silebilir
return $widget->tenant_id === tenant()->id;
}
return $user->hasModulePermission('widgetmanagement', 'delete');
}
}
📁 routes/web.php
// Root-only routes
Route::middleware(['auth', 'root'])->group(function() {
Route::get('/admin/system-settings', [SystemController::class, 'index']);
Route::post('/admin/create-tenant', [TenantController::class, 'store']);
});
// Admin routes (tenant-aware)
Route::middleware(['auth', 'admin'])->prefix('admin')->group(function() {
Route::resource('blog', BlogController::class);
Route::resource('pages', PageController::class);
});
// Spatie middleware kullanımı
Route::middleware(['role:root'])->group(function() {
Route::get('/debug/queries', ...);
});
Route::middleware(['role:admin|editor'])->group(function() {
Route::get('/admin/dashboard', ...);
});
Route::middleware(['permission:blog.create'])->group(function() {
Route::post('/admin/blog', ...);
});