Kritik Sistem Analizi

Muzibu Device Limit Sistemi

Limit=1, Uzun Session (5 Yil), auth_session_lifetime Setting

21 Aralik 2025 Tenant: 1001 Limit: 1 Cihaz

Device (Cihaz) Tanimi - KRITIK!

Device = Tarayici Instance (Browser)

Session veya IP degil, tarayici bazli sayim yapiliyor:

Ayni Cihaz (1 Device)

  • Chrome'da login → logout → tekrar Chrome'da login
  • Session expire → ayni tarayicida tekrar giris
  • mzb_login_token cookie eslesiyor

Farkli Cihaz (2 Device)

  • +Ayni PC: Chrome + Firefox = 2 cihaz
  • +PC + Mobil = 2 cihaz
  • Cookie yok veya eslesmiyorsa = yeni cihaz

Limit=1 demek: Kullanici ayni anda sadece 1 tarayicida aktif olabilir. Farkli tarayicidan giris yaparsa eski tarayici otomatik atilir (LIFO).

Temel Gereksinimler

1
Cihaz Limiti
Kullanici ayni anda sadece 1 tarayicida aktif olabilir
5 Yil
Maksimum Oturum
auth_session_lifetime setting'den ayarlanir
Ayni Tarayici
mzb_login_token cookie ile tanimlanir

ANA SORUN COZULDU! (21 Aralik 2025 - 20:00)

Eski Kod (HATALI) - DUZELTILDI

public function registerSession(User $user)
{
    // ❌ Cookie kontrolu YOK!
    $loginToken = bin2hex(random_bytes(32));
    // Sonuc: Ayni tarayici bile yeni cihaz!
}

✅ Yeni Kod (UYGULANDI)

public function registerSession(User $user)
{
    // ✅ 1. Cookie kontrol et
    $existingToken = request()->cookie('mzb_login_token');
    if ($existingToken) {
        $existing = DB::table('user_active_sessions')
            ->where('login_token', $existingToken)->first();
        if ($existing) {
            // AYNI TARAYICI - guncelle
            $existing->update([...]);
            return; // YENi TOKEN OLUSTURMA!
        }
    }
    // ✅ 2. LIFO - eski session'lari sil
    // ✅ 3. Yeni token olustur
}

DeviceService.php:50-144

Yapilan Duzeltmeler:

  • ✅ Cookie kontrolu eklendi (mzb_login_token)
  • ✅ Ayni tarayici tespiti → mevcut kayit guncelleniyor
  • ✅ LIFO aktif → farkli tarayicidan giris → eski otomatik siliniyor
  • ✅ Cookie suresi auth_session_lifetime setting'den aliniyor

Genel Ilerleme

0%
0Toplam
0Tamamlanan
0Kritik
0Kalan

auth_session_lifetime Setting

Basit Anlatim

Admin paneldeki "Oturum Suresi (dakika)" alanina yazilan deger:

  • 10080 = 1 hafta
  • 43200 = 1 ay
  • 525600 = 1 yil
  • 2628000 = 5 yil

Teknik Kullanim

$lifetime = (int) setting('auth_session_lifetime', 10080);
$expiresAt = now()->addMinutes($lifetime);
cookie('mzb_login_token', $token, $lifetime);

Ayni Tarayici Tespiti (Cookie Bazli)

Mantik:

  1. Kullanici giris yapar → mzb_login_token olusur
  2. Token cookie'ye + DB'ye kaydedilir
  3. Ayni tarayicidan tekrar giris → cookie ONCE kontrol edilir
  4. Token eslesirse → mevcut kayit guncellenir, YENI CIHAZ OLUSTURULMAZ
  5. Eslesmezse (farkli tarayici) → LIFO ile eski kick edilir
// DOGRU AKIS:
$existingToken = request()->cookie('mzb_login_token');

if ($existingToken) {
    $existing = DB::table('user_active_sessions')
        ->where('user_id', $user->id)
        ->where('login_token', $existingToken)
        ->first();

    if ($existing) {
        // AYNI TARAYICI - sadece guncelle
        $existing->update([
            'session_id' => session()->getId(),
            'last_activity' => now()
        ]);
        return; // Yeni token OLUSTURMA!
    }
}

// FARKLI TARAYICI - LIFO uygula, eski at

Diger Kritik Hatalar

1 Redis ve DB Senkronize Degil
Session silinirken sadece DB temizleniyor, Redis'te session acik kaliyor.
// HATALI: DB::delete() ama Redis hala acik!
// DOGRU: DB + Redis + Cache hepsi atomic silinmeli
2 LIFO Devre Disi
enforceDeviceLimit() yorum satirinda. Farkli tarayicidan giris yapilinca eski oturum kapatilmiyor.
// DeviceService.php:92-94
// $this->enforceDeviceLimit($user, $sessionId); // YORUM SATIRINDA!
3 Race Condition
Iki farkli tarayicidan ayni anda login → ikisi de DB'ye yaziyor → limit asiliyor.
// Cozum: Redis distributed lock
$lock = Cache::lock("user_login:{$userId}", 10);
4 Session ID Regenerate Sorunu
Livewire session ID degistiriyor, DB'deki ID eslesmeyince kullanici atiliyor.
// Cozum: session_id yerine login_token kullan
// login_token degismiyor, guvenilir identifier
5 Iki DeviceService Sinifi
App\Services\Auth\DeviceService (ESKi - sessions tablosu) ve Modules\Muzibu\...\DeviceService (YENi - user_active_sessions) karisik.
6 Stream API Kontrolsuz
SongStreamController device limit kontrolu yorum satirinda. Atilan cihaz muzik dinleyebiliyor.

Silinecek / Duzeltilecek Kodlar

Dosya Aksiyon
App\Services\Auth\DeviceService.phpSIL
CheckDeviceLimit middlewareYENIDEN YAZ
handlePostLoginDeviceLimit()SIL (bos metod)
updateSessionActivity() tehlikeli kisimSIL
Device selection modal (login.blade)KALDIR (LIFO ile gereksiz)

Detayli TODO Listesi

1 Faz 1: Kritik Duzeltmeler (ACIL)

2 Faz 2: Kod Temizligi

3 Faz 3: Test Senaryolari (Limit=1, Device=Browser)

4 Faz 4: Cron ve Temizlik

Onerilen Algoritma (Tam Versiyon)

/**
 * Device = Browser (Tarayici)
 * - Ayni tarayici = ayni cihaz (cookie ile tespit)
 * - Farkli tarayici = farkli cihaz (LIFO uygula)
 */
function registerSession(User $user): void
{
    $lifetime = (int) setting('auth_session_lifetime', 10080);
    $existingToken = request()->cookie('mzb_login_token');

    // 1. AYNI TARAYICI MI? (Cookie kontrolu)
    if ($existingToken) {
        $existing = DB::table('user_active_sessions')
            ->where('user_id', $user->id)
            ->where('login_token', $existingToken)
            ->first();

        if ($existing) {
            // AYNI TARAYICI - Mevcut kaydi guncelle
            DB::table('user_active_sessions')
                ->where('id', $existing->id)
                ->update([
                    'session_id' => session()->getId(),
                    'last_activity' => now(),
                    'expires_at' => now()->addMinutes($lifetime),
                ]);

            // Cookie'yi yenile (sure uzat)
            cookie()->queue('mzb_login_token', $existingToken, $lifetime);
            return; // YENI TOKEN OLUSTURMA!
        }
    }

    // 2. FARKLI TARAYICI - Lock al (race condition)
    $lock = Cache::lock("user_login:{$user->id}", 10);
    if (!$lock->get()) {
        throw new \Exception("Lutfen birkaç saniye bekleyin...");
    }

    try {
        // 3. LIFO - Tum eski session'lari at (Limit=1)
        DB::table('user_active_sessions')
            ->where('user_id', $user->id)
            ->get()
            ->each(function($session) {
                // Atomic terminate: DB + Redis + Cache
                $this->terminateSessionAtomic($session);
            });

        // 4. Yeni session olustur
        $loginToken = bin2hex(random_bytes(32));

        DB::table('user_active_sessions')->insert([
            'user_id' => $user->id,
            'login_token' => $loginToken,
            'session_id' => session()->getId(),
            'device_type' => $this->getDeviceType(),
            'browser' => $agent->browser(),
            'expires_at' => now()->addMinutes($lifetime),
            'created_at' => now(),
        ]);

        // 5. Cookie olustur
        cookie()->queue('mzb_login_token', $loginToken, $lifetime);

    } finally {
        $lock->release();
    }
}

Gorsel Akis Semasi

┌─────────────────────────────────────────────────────────────┐
│                     KULLANICI LOGIN                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
                ┌─────────────────────────┐
                │  mzb_login_token        │
                │  cookie var mi?         │
                └─────────────────────────┘
                     │              │
                    VAR            YOK
                     │              │
                     ▼              ▼
          ┌──────────────┐  ┌──────────────────┐
          │ DB'de token  │  │ FARKLI TARAYICI  │
          │ eslesiyor mu?│  │ (Yeni cihaz)     │
          └──────────────┘  └──────────────────┘
              │      │              │
            EVET   HAYIR            │
              │      │              │
              ▼      └──────────────┤
    ┌─────────────────┐             │
    │ AYNI TARAYICI   │             │
    │ Mevcut kaydi    │             ▼
    │ GUNCELLE        │    ┌─────────────────┐
    │ (yeni token YOK)│    │ 1. Lock al      │
    └─────────────────┘    │ 2. LIFO: eski   │
              │            │    session'lari │
              │            │    ATOMIC sil   │
              │            │ 3. Yeni token   │
              │            │    olustur      │
              │            │ 4. Cookie yaz   │
              │            └─────────────────┘
              │                    │
              └────────┬───────────┘
                       │
                       ▼
            ┌──────────────────┐
            │ DB'de 1 kayit    │
            │ (Limit=1 OK)     │
            └──────────────────┘
                        

Dosya Referanslari

DosyaSatirAciklama
Modules/Muzibu/app/Services/DeviceService.php58-60🔥 ANA SORUN: Cookie kontrolu yok
Modules/Muzibu/app/Services/DeviceService.php92-94LIFO yorum satirinda
app/Services/Auth/DeviceService.php1-99Eski sinif (SIL)
app/Http/Middleware/CheckDeviceLimit.php1-55Devre disi (return next)
app/Http/Controllers/Api/Auth/AuthController.php164-251checkSession API
Modules/Muzibu/.../SongStreamController.php75-84Stream kontrolu devre disi