Gereksinimler ve Ön Hazırlık
Uygulamaya başlamadan önce bilgisayarınızda Node.js'in 20.x veya daha güncel bir sürümünün yüklü olması gerekmektedir. Projenizi başlatmak ve gerekli kütüphaneleri kurmak için terminalinizi kullanacağız.
Proje klasörünüzü oluşturun ve aşağıdaki komutları sırasıyla çalıştırarak gerekli bağımlılıkları yükleyin:
mkdir node-jwt-auth
cd node-jwt-auth
npm init -y
npm install express jsonwebtoken bcryptjs dotenv
Burada kullandığımız jsonwebtoken paketi token oluşturma ve doğrulama işlemleri için, bcryptjs ise şifreleri veritabanına kaydetmeden önce güvenli bir şekilde hash'lemek (kriptografik olarak özetlemek) için kullanılır.
Adım 1: Kullanıcı Kaydı ve Şifre Güvenliği
Kullanıcı veritabanına kaydedilirken şifreler asla düz metin (plain text) olarak saklanmamalıdır. Bunun yerine, bcryptjs kullanarak şifreleri hash'lemeliyiz. Bu işlem, veritabanınız ele geçirilse bile kullanıcı şifrelerinin korunmasını sağlar.
const bcrypt = require('bcryptjs');
async function registerUser(password) {
const saltRounds = 12; // Güvenlik için 12 tur hashleme
const hashedPassword = await bcrypt.hash(password, saltRounds);
return hashedPassword;
}
Yukarıdaki kod, şifreyi geri döndürülemez bir formata dönüştürür. saltRounds değeri, hashleme işleminin karmaşıklığını belirler; 10 ile 12 arası günümüz donanımları için idealdir.
Adım 2: Json Web Token Oluşturma (Login Süreci)
Kullanıcı giriş yaptığında, kimliğini kanıtlayan bir token üretiriz. Bu token, kullanıcının ID'sini ve yetkilerini içeren bir payload (yük) taşır. Token'ı imzalarken gizli bir anahtar (secret key) kullanmak, token'ın sunucu dışında değiştirilmesini engeller.
const jwt = require('jsonwebtoken');
require('dotenv').config();
function generateAccessToken(user) {
return jwt.sign({ id: user.id, email: user.email }, process.env.JWT_SECRET, {
expiresIn: '1h' // Token 1 saat sonra geçersiz olur
});
}
Burada process.env.JWT_SECRET değişkenini kullanmak, gizli anahtarınızı kodun içine doğrudan yazmanızı engeller. Bu anahtarı asla GitHub gibi platformlarda paylaşmayın.
Adım 3: Kimlik Doğrulama Middleware'i Yazmak
Express.js'te korumalı rotalara erişimi denetlemek için bir "middleware" (ara katman yazılımı) kullanırız. Bu fonksiyon, gelen her isteğin başlığındaki (header) Authorization kısmını kontrol eder ve token'ın geçerliliğini doğrular.
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.status(401).json({ message: 'Token bulunamadı' });
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ message: 'Geçersiz token' });
req.user = user;
next();
});
}
Bu kod, token doğrulanırsa kullanıcı bilgilerini req.user nesnesine ekler ve isteğin devam etmesine izin verir. Aksi takdirde 403 (Forbidden) hatası döndürür.
Adım 4: Korumalı Rotaları Kullanma
Artık oluşturduğumuz middleware'i kullanarak sadece giriş yapmış kullanıcıların erişebileceği rotalar tanımlayabiliriz. Bu, uygulamanızın profil sayfası veya veri yönetimi gibi bölümleri için zorunludur.
app.get('/profile', authenticateToken, (req, res) => {
res.json({ message: 'Hoş geldiniz!', user: req.user });
});
Bu rotaya yapılan isteklerde, istemcinin Authorization: Bearer başlığını göndermesi gerekir. Aksi takdirde sunucu erişimi reddedecektir.
Yöntem Karşılaştırması: JWT vs Session
| Özellik | JWT | Session (Oturum) |
|---|---|---|
| Depolama | İstemci (Client) | Sunucu (Server) |
| Ölçeklenebilirlik | Yüksek (Stateless) | Düşük (Stateful) |
| İptal Etme | Zor (Blacklist gerekir) | Kolay (Session silinir) |
Kritik Güvenlik Uyarısı: JWT'leri asla localStorage içerisinde saklamayın; bu XSS saldırılarına karşı savunmasız bırakır. Mümkünse "HttpOnly" ve "Secure" flag'lerine sahip "Cookie" yapısını tercih edin.
Sıkça Sorulan Sorular
JWT'nin süresi dolarsa ne yapmalıyım?
Kullanıcıyı tekrar giriş yapmaya zorlamak yerine, "Refresh Token" mekanizması kurarak yeni bir erişim token'ı almasını sağlayabilirsiniz.
Token'ı veritabanında saklamalı mıyım?
JWT'nin temel amacı durumsuz (stateless) olmaktır. Ancak güvenlik gereği, iptal edilebilen token'lar için veritabanında bir "blacklist" tutulabilir.
Neden HMAC SHA256 kullanmalıyım?
JWT imzalama algoritmaları arasında en güvenli ve yaygın olanıdır. Sunucu tarafındaki gizli anahtarınızla token'ın bütünlüğünü garanti altına alır.
Payload içerisine şifre koyabilir miyim?
Kesinlikle hayır. JWT'ler Base64 ile kodlanır ve herkes tarafından içeriği okunabilir. Payload içine asla hassas veri koymayın.
Hangi kütüphaneyi kullanmak daha güvenli?
jsonwebtoken kütüphanesi topluluk tarafından en çok test edilmiş ve desteklenen standarttır.
Sorumluluk Reddi: Bu rehberdeki kodlar eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka güvenlik denetimlerinden geçirin ve güncel güvenlik açıklarını (CVE) takip edin.
JWT Uygulamalarında Performans Optimizasyonu
JWT tabanlı kimlik doğrulama sistemlerinde, her istekte token'ın doğrulanması CPU üzerinde ek bir yük oluşturur. Özellikle yüksek trafikli uygulamalarda, kriptografik imza doğrulama işlemleri darboğaz yaratabilir. Performansı artırmak için şu stratejileri izleyebilirsiniz:
- Token Boyutunu Küçük Tutun: Payload içerisine sadece gerekli olan
userIdverolegibi verileri ekleyin. Gereksiz veriler, her HTTP isteğinin boyutunu artırarak bant genişliğini tüketir. - Doğrulama Sürecini Hızlandırın: Eğer uygulamanız çok sayıda mikroservis içeriyorsa, her servisin token'ı doğrulaması yerine bir "API Gateway" kullanarak merkezi doğrulama yapın.
- Redis Kullanımı: Geçersiz kılınan (blacklist) token'ları veritabanı yerine Redis gibi bellek içi (in-memory) veri depolarında tutun. Bu, sorgu süresini milisaniyeler seviyesine indirir.
JWT Hata Ayıklama ve İzleme (Debugging)
Geliştirme sürecinde JWT ile ilgili hataları ayıklamak bazen karmaşık olabilir. Token'ın neden reddedildiğini anlamak için standart hata kodlarını ve hata mesajlarını doğru yönetmek gerekir. Aşağıdaki örnek, middleware içerisinde detaylı hata yönetimi yapmanızı sağlar:
const jwt = require('jsonwebtoken');
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Token bulunamadı' });
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) {
if (err.name === 'TokenExpiredError') {
return res.status(403).json({ error: 'Token süresi dolmuş' });
}
if (err.name === 'JsonWebTokenError') {
return res.status(403).json({ error: 'Geçersiz token imzası' });
}
return res.status(403).json({ error: 'Yetkilendirme hatası' });
}
req.user = user;
next();
});
};
Yaygın Hata Senaryoları
| Hata Türü | Olası Neden | Çözüm |
|---|---|---|
| TokenExpiredError | Token süresi dolmuştur. | Refresh token kullanarak yeni bir access token alın. |
| JsonWebTokenError | İmza uyuşmazlığı veya bozuk token. | SECRET_KEY değişkenini kontrol edin. |
| NotBeforeError | Token henüz aktif değil. | Sunucu saati ile token oluşturma saati arasındaki farkı kontrol edin. |
Deployment ve Güvenlik İpuçları
Uygulamanızı canlı ortama alırken JWT güvenliğini en üst düzeye çıkarmak için şu adımları mutlaka uygulayın:
- HTTPS Kullanımı: Token'lar ağ üzerinden düz metin olarak iletilmemelidir. Mutlaka SSL/TLS sertifikası kullanın.
- Secret Key Yönetimi:
ACCESS_TOKEN_SECRETdeğerini asla kaynak kod içerisinde (hardcoded) bırakmayın. Ortam değişkenlerini (environment variables) veya AWS Secrets Manager gibi servisleri kullanın. - Secure Flag: Eğer token'ı cookie içerisinde saklıyorsanız,
httpOnly: truevesecure: truebayraklarını mutlaka aktif edin.
Sonuç
Node.js ile JWT kullanarak kimlik doğrulama sistemi kurmak, uygulamanızın ölçeklenebilirliği için atılacak en doğru adımlardan biridir. Bu rehberde, şifre hashleme, token oluşturma ve middleware ile doğrulama süreçlerini öğrendiniz. Bir sonraki adımda, "Refresh Token" stratejilerini araştırarak kullanıcı deneyimini kesintisiz hale getirebilirsiniz.


Yorumlar (0)
Yorum Yaz