UZMAN
Session Management
Multi-instance uygulama session'larının Redis ile merkezi yönetimi.
Kod örneği görünümü
Bu sayfadaki eşleşen örnekleri seçilen istemciye göre gösterir.
Ne Zaman Redis Session Kullan / Kullanma
| Kullan | Kullanma | Gerçek Hayat |
|---|---|---|
| Multi-instance/pod uygulama — session paylaşımı gerekli | Tek pod, in-memory session yeterli | SaaS: 5 pod arkasında LB — hangi pod'a düşerse düşsün session geçerli |
| Sticky session istemiyorsun (LB esnekliği) | JWT-only auth (stateless, session yok) | E-ticaret: Pod restart'ta kullanıcı çıkış yapmaz |
| Session içeriği küçük (userId, role, preferences) | Büyük objeleri session'da tutmak (dosya, sepet detayı) | Chat app: Online status + last-seen → küçük Hash, sliding TTL |
| Hızlı invalidation gerekli (force logout, güvenlik) | Sadece login/logout, arada session'a erişim yok | Fintech: Fraud algılandığında anında tüm session'ları DEL |
Gerçek hayat senaryosu — Force logout: Admin panelden kullanıcıyı "tüm cihazlardan çıkar" yapmak istiyorsun. Redis'te
SCAN session:* MATCH *userId:1001*+DELile tüm session'larını anında sil. JWT token'ları expire olana kadar geçerli kalır — Redis session ise anında invalidate edilir.
HSET session:abc123 userId "1001" role "admin" loginAt "1716825600"
EXPIRE session:abc123 1800 # 30dk inactivity timeout
# Her request'te:
EXPIRE session:abc123 1800 # sliding expiration
HGETALL session:abc123
// Program.cs — Redis-backed distributed session
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "session:";
});
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
// Custom session store (daha fazla kontrol)
public class RedisSessionService
{
private readonly IDatabase _redis;
public RedisSessionService(IConnectionMultiplexer mux)
=> _redis = mux.GetDatabase();
public async Task CreateSessionAsync(string sessionId, SessionData data)
{
var key = $"session:{sessionId}";
await _redis.HashSetAsync(key, new HashEntry[]
{
new("userId", data.UserId),
new("role", data.Role),
new("loginAt", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())
});
await _redis.KeyExpireAsync(key, TimeSpan.FromMinutes(30));
}
public async Task<SessionData?> GetSessionAsync(string sessionId)
{
var key = $"session:{sessionId}";
var entries = await _redis.HashGetAllAsync(key);
if (entries.Length == 0) return null;
// Sliding expiration
await _redis.KeyExpireAsync(key, TimeSpan.FromMinutes(30));
var dict = entries.ToDictionary(e => e.Name.ToString(), e => e.Value.ToString());
return new SessionData
{
UserId = dict.GetValueOrDefault("userId") ?? "",
Role = dict.GetValueOrDefault("role") ?? ""
};
}
public async Task DestroySessionAsync(string sessionId)
{
await _redis.KeyDeleteAsync($"session:{sessionId}");
}
// Session Fixation koruması — login/role değişiminde ID yenile
public async Task<string> RotateSessionAsync(string oldSessionId)
{
var oldKey = $"session:{oldSessionId}";
var entries = await _redis.HashGetAllAsync(oldKey);
if (entries.Length == 0)
throw new InvalidOperationException("Session not found");
// Yeni session ID üret
var newSessionId = Convert.ToBase64String(
RandomNumberGenerator.GetBytes(32));
var newKey = $"session:{newSessionId}";
// Veriyi yeni key'e taşı
await _redis.HashSetAsync(newKey, entries);
await _redis.KeyExpireAsync(newKey, TimeSpan.FromMinutes(30));
// Eski session'ı sil
await _redis.KeyDeleteAsync(oldKey);
return newSessionId;
}
}
Session Fixation: Kullanıcı login olduğunda veya yetki seviyesi değiştiğinde mutlaka
RotateSessionAsyncçağır. Eski session ID'yi geçersiz kıl — aksi halde saldırgan eski ID ile oturum ele geçirebilir (OWASP A07).