emirhanHCL 1
emirhanHCL
farkmt2official 1
farkmt2official
mannaxxx 1
mannaxxx
Hikaye Ekle

[NODE JS] Express'te Auth Middleware Yazma

  • Konuyu başlatan Konuyu başlatan Silverhand
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 1
  • Görüntüleme Görüntüleme 10

Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!

nodejs.png


[NODE JS] Express'te Auth Middleware Yazma​


Kimlik doğrulama (authentication) ve yetkilendirme (authorization) web uygulamalarının en kritik bileşenlerinden biridir. Authentication kullanıcının kim olduğunu doğrular, authorization ise o kullanıcının ne yapabileceğini belirler. Express'te bu kontrolleri middleware olarak yazmak en temiz ve tekrar kullanılabilir yaklaşımdır.

JWT (JSON Web Token) modern web uygulamalarında en yaygın kimlik doğrulama yöntemi. Kullanıcı giriş yaptığında sunucu bir JWT oluşturur ve istemciye gönderir. İstemci bu token'ı her istekte Authorization header'ında gönderir. Sunucu token'ı doğrulayarak kullanıcıyı tanır. Session tabanlı authentication'dan farkı sunucuda oturum bilgisi tutulmamasıdır, bu da ölçeklenebilirlik açısından avantaj sağlar.

Ben ilk auth middleware'imi yazarken JWT secret'ı kodun içine yazmıştım. Bir gün GitHub'a push ettim ve birisi bu secret'ı bulup sisteme sızdı. O günden sonra secret'ları her zaman environment variable olarak tutuyorum ve .env dosyasını .gitignore'a ekliyorum. Bu çok temel bir güvenlik kuralı ama inanılmaz sık yapılan bir hata.

Auth middleware genellikle şu adımları izler: Authorization header'ını kontrol et, token'ı çıkar, token'ı doğrula, kullanıcı bilgisini req objesine ekle, next() ile devam et. Herhangi bir adımda sorun varsa 401 Unauthorized döndür. Bu basit akışı bir kere doğru yazarsanız tüm uygulamanızda kullanabilirsiniz.

Token'ın süresi dolmuş olabilir. JWT'de exp claim'i ile süre belirlenir ve süre geçtiğinde token geçersiz olur. Bu durumda 401 döndürüp kullanıcıyı yeniden giriş yapmaya yönlendirirsiniz. Refresh token mekanizması ile kullanıcının sürekli giriş yapmasını engelleyebilirsiniz.

Role-based access control (RBAC) yetkilendirme için yaygın bir pattern. Kullanıcılara roller atanır (admin, editor, user) ve her endpoint hangi rollerin erişebileceğini belirtir. Middleware factory pattern'i ile bu kontrolü çok temiz bir şekilde yapabilirsiniz: authorize('admin', 'editor') gibi.

API key authentication dış servisler ve üçüncü parti entegrasyonlar için daha uygundur. Kullanıcıya bir API anahtarı verilir ve her istekte bu anahtar gönderilir. JWT kadar esnek değildir ama basit API'ler için yeterlidir. Genellikle X-API-Key header'ında veya query parametresinde gönderilir.

Rate limiting ile brute force saldırılarını engelleyebilirsiniz. Belirli bir IP'den belirli bir sürede yapılabilecek istek sayısını sınırlamak önemli bir güvenlik önlemi. Auth endpoint'lerinde bu limite daha da düşük tutmanızı öneririm. Başarısız giriş denemelerini de loglamalısınız.

Token'ı blacklist'e almak logout işlemi için gerekli. JWT stateless olduğu için sunucu tarafında bir iptal mekanizması yoktur. Token süresi dolana kadar geçerli kalır. Bunu çözmek için bir token blacklist tutabilirsiniz. Redis bu iş için ideal çünkü hem hızlı hem de TTL desteği var.

Password hash'leme de auth konusunun önemli bir parçası. Şifreleri asla plain text saklamayın. bcrypt veya argon2 ile hash'leyin. Salt otomatik eklenir ve rainbow table saldırılarına karşı koruma sağlar. bcrypt.compare ile giriş sırasında şifreyi doğrularsınız.

JavaScript:
const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

// Basit JWT benzeri token sistemi (gercek projede jsonwebtoken paketi kullanin)
const JWT_SECRET = process.env.JWT_SECRET || 'bu-secret-env-den-gelmeli-sakla-beni';
const TOKEN_SURESI = 3600000; // 1 saat (ms)

// Kullanici veritabani (normalde gercek DB kullanin)
const kullanicilar = [
  {{ id: 1, email: 'admin@test.com', sifre: hashSifre('admin123'), rol: 'admin', ad: 'Admin' }},
  {{ id: 2, email: 'editor@test.com', sifre: hashSifre('editor123'), rol: 'editor', ad: 'Editor' }},
  {{ id: 3, email: 'user@test.com', sifre: hashSifre('user123'), rol: 'user', ad: 'Kullanici' }},
];

// Token deposu (gercekte Redis kullanin)
const aktifTokenlar = new Map();
const karaListe = new Set();

// Basit hash fonksiyonu (gercekte bcrypt kullanin)
function hashSifre(sifre) {{
  return crypto.createHash('sha256').update(sifre + JWT_SECRET).digest('hex');
}}

// Token olustur
function tokenOlustur(kullanici) {{
  const payload = {{
    id: kullanici.id,
    email: kullanici.email,
    rol: kullanici.rol,
    iat: Date.now(),
    exp: Date.now() + TOKEN_SURESI,
  }};
  const tokenData = Buffer.from(JSON.stringify(payload)).toString('base64');
  const signature = crypto
    .createHmac('sha256', JWT_SECRET)
    .update(tokenData)
    .digest('hex');
  return `${{tokenData}}.${{signature}}`;
}}

// Token dogrula
function tokenDogrula(token) {{
  try {{
    const [tokenData, signature] = token.split('.');
    const beklenenImza = crypto
      .createHmac('sha256', JWT_SECRET)
      .update(tokenData)
      .digest('hex');

    if (signature !== beklenenImza) return null;

    const payload = JSON.parse(Buffer.from(tokenData, 'base64').toString());

    if (payload.exp < Date.now()) return null;

    return payload;
  }} catch {{
    return null;
  }}
}}

// ===== AUTH MIDDLEWARE =====

function authMiddleware(req, res, next) {{
  const authHeader = req.headers.authorization;

  if (!authHeader) {{
    return res.status(401).json({{
      hata: 'Authorization header eksik',
      ipucu: 'Bearer <token> formatinda gonderin',
    }});
  }}

  if (!authHeader.startsWith('Bearer ')) {{
    return res.status(401).json({{ hata: 'Token formati hatali. Bearer <token> kullanin' }});
  }}

  const token = authHeader.split(' ')[1];

  if (karaListe.has(token)) {{
    return res.status(401).json({{ hata: 'Token gecersiz kilinmis (logout yapilmis)' }});
  }}

  const payload = tokenDogrula(token);
  if (!payload) {{
    return res.status(401).json({{ hata: 'Token gecersiz veya suresi dolmus' }});
  }}

  req.kullanici = payload;
  req.token = token;
  next();
}}

// ===== YETKILENDIRME MIDDLEWARE FABRIKASI =====

function yetkilendir(...izinliRoller) {{
  return (req, res, next) => {{
    if (!req.kullanici) {{
      return res.status(401).json({{ hata: 'Kimlik dogrulanmadi' }});
    }}

    if (!izinliRoller.includes(req.kullanici.rol)) {{
      return res.status(403).json({{
        hata: 'Bu islemi yapmaya yetkiniz yok',
        gerekliRol: izinliRoller,
        mevcutRol: req.kullanici.rol,
      }});
    }}

    next();
  }};
}}

// ===== GIRIS ve CIKIS ENDPOINTLERI =====

app.post('/api/giris', (req, res) => {{
  const {{ email, sifre }} = req.body;

  if (!email || !sifre) {{
    return res.status(400).json({{ hata: 'Email ve sifre zorunludur' }});
  }}

  const kullanici = kullanicilar.find(k => k.email === email);
  if (!kullanici || kullanici.sifre !== hashSifre(sifre)) {{
    return res.status(401).json({{ hata: 'Email veya sifre hatali' }});
  }}

  const token = tokenOlustur(kullanici);
  aktifTokenlar.set(token, kullanici.id);

  res.json({{
    mesaj: 'Giris basarili',
    token,
    kullanici: {{ id: kullanici.id, ad: kullanici.ad, rol: kullanici.rol }},
  }});
}});

app.post('/api/cikis', authMiddleware, (req, res) => {{
  karaListe.add(req.token);
  aktifTokenlar.delete(req.token);
  res.json({{ mesaj: 'Cikis basarili' }});
}});

// ===== KORUMALI ENDPOINTLER =====

// Herkes erisebilir (login gerekli)
app.get('/api/profil', authMiddleware, (req, res) => {{
  const kullanici = kullanicilar.find(k => k.id === req.kullanici.id);
  res.json({{
    id: kullanici.id,
    ad: kullanici.ad,
    email: kullanici.email,
    rol: kullanici.rol,
  }});
}});

// Sadece admin
app.get('/api/admin/kullanicilar', authMiddleware, yetkilendir('admin'), (req, res) => {{
  const liste = kullanicilar.map(k => ({{ id: k.id, ad: k.ad, email: k.email, rol: k.rol }}));
  res.json(liste);
}});

// Admin ve editor
app.post('/api/icerik', authMiddleware, yetkilendir('admin', 'editor'), (req, res) => {{
  res.status(201).json({{ mesaj: 'Icerik olusturuldu', yazan: req.kullanici.email }});
}});

// Public endpoint
app.get('/api/acik', (req, res) => {{
  res.json({{ mesaj: 'Bu endpoint herkese acik' }});
}});

app.listen(3000, () => {{
  console.log('Auth middleware sunucusu port 3000\'de');
  console.log('Test: POST /api/giris {{"email":"admin@test.com","sifre":"admin123"}}');
}});

Auth middleware yazarken güvenliği her zaman birinci öncelik olarak tutun. OWASP Top 10 listesini inceleyin ve yaygın güvenlik açıklarına karşı önlem alın. Production'da mutlaka bcrypt veya argon2 kullanın, JWT secret'ı güçlü tutun ve HTTPS zorunlu kılın.
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst