mannaxxx 1
mannaxxx
Agora Metin2 1
Agora Metin2
[DEV]AB 1
[DEV]AB
kaptanmikro1 1
kaptanmikro1
Hikaye Ekle

[NODE JS] JWT Token Oluşturma ve Doğrulama

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

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] JWT Token Oluşturma ve Doğrulama​


Modern web uygulamalarında kimlik doğrulama, oturum tabanlı (session-based) yaklaşımdan token tabanlı yaklaşıma doğru evrildi. JWT (JSON Web Token) bu dönüşümün en popüler aracıdır. Ben de birkaç yıl önce oturum tabanlı bir sistemden JWT'ye geçiş yaptım ve ölçeklenebilirlik sorunlarımın büyük kısmı çözüldü. Artık birden fazla sunucu arasında oturum paylaşmak için Redis'e ihtiyacım yoktu.

JWT üç parçadan oluşur ve bunlar nokta ile ayrılır: Header.Payload.Signature. Header, token'ın tipini ve kullanılan algoritmayı belirtir. Payload, taşınan verileri (claims) içerir. Signature ise header ve payload'ın gizli bir anahtar ile imzalanmış halidir. Bu imza, token'ın değiştirilmediğini garanti eder.

Payload içinde standart alanlar (claims) vardır: iss (issuer - veren), sub (subject - konu), aud (audience - hedef kitle), exp (expiration - son kullanma), nbf (not before - öncesinde geçersiz), iat (issued at - verilme zamanı), jti (JWT ID - benzersiz kimlik). Bunlara ek olarak kendi özel alanlarınızı da ekleyebilirsiniz.

Önemli bir nokta: JWT payload'ı şifrelenmez, sadece Base64 ile kodlanır. Yani herkes payload'ı okuyabilir. Bu nedenle hassas bilgileri (şifre, kredi kartı numarası gibi) asla payload'a koymayın. JWT'nin amacı gizlilik değil, bütünlük ve kimlik doğrulamadır.

Node.js'te jsonwebtoken paketi, JWT işlemleri için standart araçtır. jwt.sign() ile token oluşturur, jwt.verify() ile doğrularsınız. Doğrulama başarısız olursa hata fırlatılır ve bu hatanın türüne göre uygun tepki verebilirsiniz: süre dolmuş, geçersiz imza, hatalı format gibi.

Token süresini belirlemek önemli bir karardır. Çok kısa süre kullanıcıyı sık sık giriş yapmaya zorlar, çok uzun süre güvenlik riski oluşturur. Genellikle access token için 15 dakika ile 1 saat arası, refresh token için 7-30 gün arası değerler kullanılır.

İmzalama algoritması seçimi de kritiktir. HS256 (HMAC-SHA256) simetrik bir algoritmadır ve aynı gizli anahtar hem imzalama hem doğrulama için kullanılır. RS256 (RSA-SHA256) asimetrik bir algoritmadır ve özel anahtar ile imzalanır, açık anahtar ile doğrulanır. Mikroservis mimarisinde RS256 tercih edilir çünkü doğrulama yapan servisin gizli anahtarı bilmesine gerek yoktur.

Güvenlik açısından birkaç kritik kural vardır. Gizli anahtarınızı yeterince uzun ve rastgele tutun, minimum 256 bit önerilir. Token'ı localStorage yerine httpOnly cookie'de saklayın. HTTPS kullanın, aksi takdirde token ele geçirilebilir. Token kara listesi mekanizması düşünün, özellikle kullanıcı çıkış yaptığında token'ı geçersiz kılmak için.

JavaScript:
// ==============================
// JWT Token Oluşturma ve Doğrulama
// ==============================
const jwt = require('jsonwebtoken');
const crypto = require('crypto');

// Gizli anahtar (production'da ortam değişkeninden alın)
const GIZLI_ANAHTAR = crypto.randomBytes(64).toString('hex');
const REFRESH_ANAHTARI = crypto.randomBytes(64).toString('hex');

// Token süreleri
const ACCESS_SURESI = '15m';  // 15 dakika
const REFRESH_SURESI = '7d';  // 7 gün

// ==============================
// Token Oluşturma
// ==============================
function accessTokenOlustur(kullanici) {
    const payload = {
        kullaniciId: kullanici.id,
        kullaniciAdi: kullanici.kullaniciAdi,
        email: kullanici.email,
        rol: kullanici.rol
    };

    const secenekler = {
        expiresIn: ACCESS_SURESI,
        issuer: 'uygulama-api',
        subject: String(kullanici.id),
        audience: 'uygulama-istemci'
    };

    const token = jwt.sign(payload, GIZLI_ANAHTAR, secenekler);
    console.log('Access token oluşturuldu.');
    console.log('Token uzunluğu:', token.length, 'karakter');

    return token;
}

function refreshTokenOlustur(kullanici) {
    const payload = {
        kullaniciId: kullanici.id,
        tip: 'refresh'
    };

    const secenekler = {
        expiresIn: REFRESH_SURESI,
        issuer: 'uygulama-api',
        subject: String(kullanici.id)
    };

    return jwt.sign(payload, REFRESH_ANAHTARI, secenekler);
}

// ==============================
// Token Doğrulama
// ==============================
function tokenDogrula(token) {
    try {
        const cozulmus = jwt.verify(token, GIZLI_ANAHTAR, {
            issuer: 'uygulama-api',
            audience: 'uygulama-istemci'
        });

        console.log('Token geçerli!');
        console.log('Kullanıcı ID:', cozulmus.kullaniciId);
        console.log('Kullanıcı adı:', cozulmus.kullaniciAdi);
        console.log('Rol:', cozulmus.rol);
        console.log('Verilme zamanı:', new Date(cozulmus.iat * 1000).toLocaleString('tr-TR'));
        console.log('Son kullanma:', new Date(cozulmus.exp * 1000).toLocaleString('tr-TR'));

        return cozulmus;
    } catch (hata) {
        if (hata instanceof jwt.TokenExpiredError) {
            console.error('Token süresi dolmuş!');
            console.error('Dolma zamanı:', hata.expiredAt);
        } else if (hata instanceof jwt.JsonWebTokenError) {
            console.error('Geçersiz token:', hata.message);
        } else if (hata instanceof jwt.NotBeforeError) {
            console.error('Token henüz geçerli değil.');
        }
        return null;
    }
}

// ==============================
// Token Yenileme (Refresh)
// ==============================
function tokenYenile(refreshToken) {
    try {
        const cozulmus = jwt.verify(refreshToken, REFRESH_ANAHTARI);

        if (cozulmus.tip !== 'refresh') {
            throw new Error('Geçersiz token tipi');
        }

        // Yeni access token oluştur
        const yeniAccessToken = accessTokenOlustur({
            id: cozulmus.kullaniciId,
            kullaniciAdi: 'veritabanından_al',
            email: 'veritabanından_al',
            rol: 'veritabanından_al'
        });

        console.log('Access token yenilendi.');
        return yeniAccessToken;
    } catch (hata) {
        console.error('Refresh token geçersiz:', hata.message);
        return null;
    }
}

// ==============================
// Token İçeriğini Çözme (Doğrulama Olmadan)
// ==============================
function tokenCoz(token) {
    // Doğrulama yapmadan payload'ı oku
    const cozulmus = jwt.decode(token, { complete: true });

    if (cozulmus) {
        console.log('
Token Yapısı:');
        console.log('Header:', JSON.stringify(cozulmus.header, null, 2));
        console.log('Payload:', JSON.stringify(cozulmus.payload, null, 2));
    }

    return cozulmus;
}

// ==============================
// Kullanım Örneği
// ==============================
async function ornekKullanim() {
    // Kullanıcı bilgileri (normalde veritabanından gelir)
    const kullanici = {
        id: 42,
        kullaniciAdi: 'mehmet_yazilimci',
        email: 'mehmet@ornek.com',
        rol: 'admin'
    };

    // Token oluştur
    console.log('=== Token Oluşturma ===');
    const accessToken = accessTokenOlustur(kullanici);
    const refreshToken = refreshTokenOlustur(kullanici);

    // Token yapısını incele
    console.log('
=== Token Yapısı ===');
    tokenCoz(accessToken);

    // Token doğrula
    console.log('
=== Token Doğrulama ===');
    const dogrulanmis = tokenDogrula(accessToken);

    // Token yenile
    console.log('
=== Token Yenileme ===');
    const yeniToken = tokenYenile(refreshToken);
}

ornekKullanim();

JWT, modern web uygulamalarının kimlik doğrulama standardıdır. Doğru kullanıldığında güvenli ve ölçeklenebilir bir çözüm sunar. Gizli anahtarınızı güvende tutun, token sürelerini mantıklı belirleyin ve hassas verileri payload'a koymayın. Bir sonraki konuda JWT'yi Express API'sinde nasıl kullanacağımızı göreceğiz.
 

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

Geri
Üst