Ders 14 / 19
Belirteç Tabanlı Kimlik Doğrulama
Durumsuz oturumda kimliğe dair her şey belirtecin taşıdığı iddialarda durur; sunucu tarafında hiçbir oturum kaydı yok. Bir yetki sorusunun bir açıklamadan mı yoksa kaynaktaki bir karşılaştırmadan mı yanıtlandığı koşturularak ayrılır; sınırlayıcı ölçüm, iptal edilmiş bir belirtecin doğrulayıcı hiçbir iptal listesine bakmadığı için süresi dolana kadar kaç adım geçerli sayılmaya devam ettiğini sayıyla gösterir.
İçindekiler
Önceki ders çağıranın rolünü hazır bir dize olarak aldı ve bu dizenin nereden geldiğini hiç sormadı. Bu ders tam o soruyu soruyor. Bir sunucu, bir çağıranın kim olduğunu iki yoldan birinden bilebilir: ya her istekte o çağırana ait bir kaydı kendi tarafında tutar, ya da kimliğe dair her şeyi çağıranın taşıdığı bir belirteçte saklar ve kendi tarafında hiçbir şey tutmaz. İkincisi durumsuz oturum: sunucunun belleğinde çağıranla ilgili sıfır kayıt var, her isteğin kimliği o isteğin kendi içinde geliyor. Bu ders belirteci modelliyor — gerçek bir anahtar, gerçek bir imza algoritması ya da gerçek bir kriptografi yordamı yazmadan — ve iki şeyi ölçüyor: belirtecin taşıdığı iddia (belirteç) sayısı, ve bir yetki sorusunun yanıtının kaynakta bir açıklamadan mı yoksa bir çağrıdan mı geldiği. Sınırlayıcı ölçüm en sona bırakılıyor, çünkü durumsuzluğun bir bedeli var ve bu bedel ancak belirtecin ömrü boyunca koşturularak görülüyor.
Oturum tabanlı bir yaklaşımda sunucu her çağıran için bir kayıt tutar; kaydı silmek çağıranı anında geçersiz kılar, çünkü her istek zaten o kayda bakar. Durumsuz yaklaşım bu bakışı hiç yapmaz — kimliğin kanıtı her istekle birlikte gelir, sunucu tarafında sorgulanacak bir kayıt yoktur. Bu fark yalnız bir uygulama ayrıntısı değil, bu dersin ölçtüğü şeyin tam kendisi.
Belirtecin Taşıdığı İddialar
Modellenen belirteç iki alan taşıyor: bir konu (çağıranın kimliği) ve bir iddialar haritası — konu hakkında taşınan her bilgi bu haritada bir anahtar-değer çifti. Üçüncü alan bir geçerlilik sonu, ama bu gerçek bir zaman damgası değil: dersin ilerleyen bölümünde kullanılacak, adım sayan bir tam sayı. Gerçek saat, gerçek süre ya da gerçek bir imza yok; belirtecin kendisi sıradan bir veri taşıyıcısı olarak modelleniyor.
// Belirtec.java — kimlige dair her seyi tasiyan durumsuz veri tasiyicisi; gecerlilikSonu gercek zaman degil, adim sayan bir tam sayi (yardimci kaynak, main yok)
import java.util.*;
record Belirtec(String konu, Map<String, String> iddialar, int gecerlilikSonu) { }
class Dogrulayici {
// durumsuz dogrulama: yalniz belirtecin kendi alanlarina ve verilen adima bakar,
// hicbir paylasilan duruma (iptal listesi, oturum deposu) erismiyor.
static boolean gecerliMi(Belirtec b, int suAn) {
return suAn <= b.gecerlilikSonu();
}
static void goster(String etiket, Object deger) {
System.out.printf("%-42s: %s%n", etiket, deger);
}
}
// IddiaSayisi.java — iki belirtecin tasidigi iddia sayisi sayiliyor; sunucu tarafinda tutulan oturum kaydi sayisi sifir
import java.util.*;
public class IddiaSayisi {
public static void main(String[] args) {
Belirtec misafir = new Belirtec("kullanici-7", Map.of("rol", "misafir"), 10);
Belirtec yonetici = new Belirtec("kullanici-2",
Map.of("rol", "yonetici", "departman", "IT", "seviye", "3"), 10);
Dogrulayici.goster("misafir belirteci, tasidigi iddia sayisi", misafir.iddialar().size());
Dogrulayici.goster("yonetici belirteci, tasidigi iddia sayisi", yonetici.iddialar().size());
Dogrulayici.goster("sunucu tarafinda tutulan oturum kaydi sayisi", 0);
}
}
misafir belirteci, tasidigi iddia sayisi : 1 yonetici belirteci, tasidigi iddia sayisi : 3 sunucu tarafinda tutulan oturum kaydi sayisi: 0
misafir bir iddia taşıyor, yonetici üç. Bu sayı sabit değil — her belirteç kendi
taşıdığı bilgi kadar ağır, ve sunucu tarafında bu bilgiyi tekrar tutan hiçbir yapı yok.
GT6. Belirteç, sunucu tarafında hiçbir oturum kaydı tutulmadan, kimliğe dair bütün
bilgiyi kendi iddiaları içinde taşır; bu, durumsuz oturumun tanımıdır. GT7. Taşınan
iddia sayısı belirteçten belirtece değişebilir, ama sunucu tarafında tutulan kayıt sayısı
her zaman sıfırdır — önceki derste ölçülen Bekci’nin ucNoktalar haritası gibi bir yapı
burada yok, çünkü ölçülecek bir çağıran durumu zaten bulunmuyor.
Gerçek bir belirteç sistemi iddiaları bir imzayla korur — belirtecin içeriği değiştirilmiş
mi diye bakan bir doğrulama adımı. Bu ders o adımı yazmıyor; imza, anahtar ve kriptografi
yordamları M24/K04 Kimlik, Erişim ve Kriptografi kursunda kuruldu ve burada tekrarlanmıyor.
Burada Belirtec sıradan bir kayıt (record), imzasız ve doğrudan üretilmiş; ölçülen şey
imzanın kendisi değil, imza doğru olduğunda bile geriye kalan iki soru — iddia ne kadar bilgi
taşıyor, ve o bilgi nasıl okunuyor.
Durumsuzluğun bu konudaki asıl kazancı, kimliği doğrulayan tarafın hiçbir paylaşılan kayda ihtiyaç duymaması. Bir çağrıyı hangi bileşenin karşıladığı önemsiz hâle geliyor, çünkü her bileşen belirteci tek başına, kendi elindeki bilgiyle doğrulayabiliyor — bir öncekinin tuttuğu bir kaydı sormasına gerek yok. Bu özellik ilerideki iki derste tekrar karşımıza çıkacak: dağıtık yapılandırma dersinde birden çok bileşenin aynı değeri görüp görmediği sorgulanacak, servis keşfi dersinde bir çağrının hangi bileşene ulaştığı hiç sabit olmayacak. Durumsuz kimlik, bu değişkenliğin bir sorun çıkarmamasının nedenlerinden biri.
Doğrulamanın Kaynağı: Açıklama mı Çağrı mı
Bir belirtecin taşıdığı iddiaların doğru olup olmadığı ayrı bir soru; bu ders yalnız
iddiaların okunma biçimini ölçüyor — “rol iddiası yönetici mi” sorusunun yanıtı nereden
geliyor? İki yol modelleniyor. Birincisi bir açıklama: yönteme konan @GerekliIddia işareti,
gerekli anahtarı ve beklenen değeri taşıyor, onu okuyan ve karşılaştıran taraf çağıran değil,
denetim sınıfının kendisi.
// GerekliIddia.java — bir yontemin gecmesi icin belirtecte hangi iddianin hangi degeri tasimasi gerektigini belirten aciklama tipi (yardimci kaynak, main yok)
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface GerekliIddia { String ad(); String deger(); }
// IddiaDenetimi.java — aciklamayi okuyup belirtecin ilgili iddiasiyla karsilastiran denetim (yardimci kaynak, main yok)
import java.lang.reflect.*;
class IddiaDenetimi {
static boolean karsilarMi(Method m, Belirtec b) {
GerekliIddia g = m.getAnnotation(GerekliIddia.class);
if (g == null) return true;
return g.deger().equals(b.iddialar().get(g.ad()));
}
}
// GizliUclar.java — panel yontemi uzerindeki isaret, hangi iddianin gerekli oldugunu soyluyor (yardimci kaynak, main yok)
class GizliUclar {
@GerekliIddia(ad = "rol", deger = "yonetici")
String panel() { return "panel-verisi"; }
}
İkinci yol kaynakta yazılı bir karşılaştırma; hiçbir işaret okunmuyor, hiçbir yansıma çalışmıyor.
// ElleDogrulama.java — ayni soru, kaynakta yazili bir karsilastirmadan yanitlaniyor (yardimci kaynak, main yok)
class ElleDogrulama {
static boolean yoneticiMi(Belirtec b) {
return "yonetici".equals(b.iddialar().get("rol"));
}
}
// DogrulamaKaynagi.java — ayni iki belirtecle, aciklama temelli ve cagri temelli denetim ayni sonucu ureterek karsilastiriliyor
import java.lang.reflect.*;
import java.util.*;
public class DogrulamaKaynagi {
public static void main(String[] args) throws Exception {
Belirtec misafir = new Belirtec("kullanici-7", Map.of("rol", "misafir"), 10);
Belirtec yonetici = new Belirtec("kullanici-2", Map.of("rol", "yonetici"), 10);
Method panel = GizliUclar.class.getDeclaredMethod("panel");
Dogrulayici.goster("aciklama: panel, misafir belirteci", IddiaDenetimi.karsilarMi(panel, misafir));
Dogrulayici.goster("aciklama: panel, yonetici belirteci", IddiaDenetimi.karsilarMi(panel, yonetici));
Dogrulayici.goster("cagri: elleDogrulama, misafir belirteci", ElleDogrulama.yoneticiMi(misafir));
Dogrulayici.goster("cagri: elleDogrulama, yonetici belirteci", ElleDogrulama.yoneticiMi(yonetici));
}
}
aciklama: panel, misafir belirteci : false aciklama: panel, yonetici belirteci : true cagri: elleDogrulama, misafir belirteci : false cagri: elleDogrulama, yonetici belirteci : true
Dört satırın sonucu ikişer ikişer birebir aynı; IddiaDenetimi.karsilarMi ile
ElleDogrulama.yoneticiMi aynı iki belirteç için aynı iki yanıtı veriyor. GT8. Aynı
“rol yönetici mi” sorusu bir açıklamadan okunarak yanıtlanabiliyor: panel yönteminin
kaynağında ne “rol” sözcüğü ne bir karşılaştırma geçiyor, karar @GerekliIddia işaretinde
duruyor. GT9. Aynı soru kaynakta yazılı bir karşılaştırmadan da yanıtlanabiliyor:
yoneticiMi yönteminin ilk satırı iddialar().get("rol") çağrısını ve karşılaştırmayı
doğrudan taşıyor. İki kaynak aynı sonucu üretiyor, ama GizliUclar sınıfının kaynağını
okuyan biri “yönetici” sözcüğünü hiç görmezken, ElleDogrulama sınıfının kaynağını okuyan
biri onu ilk satırda buluyor.
IddiaDenetimi.karsilarMi yönteminin bir de üçüncü hâli var: @GerekliIddia işareti hiç
yoksa yöntem doğrudan true döner — önceki dersteki varsayılan-açık kurulumun aynısı, burada
tek satırlık bir kısayolla. Bu, açıklama ile çağrı arasındaki asıl farkı gösteriyor: açıklama
tabanlı denetim bütün GizliUclar sınıfı için tek bir yerde tanımlı, yeni bir yöntem
eklendiğinde default olarak izin veriyor ve gerekiyorsa üzerine işaret konuyor. Çağrı tabanlı
denetimde ise her yeni yöntem kendi karşılaştırmasını kendi yazmak zorunda; bir yöntem bu
satırı unutursa, unutulduğu hiçbir yerde görünmez — kaynak eksiksiz derlenir, çalışır, ve
denetimsiz kalır.
Durumsuzluğun Bedeli: İptal Edilmiş Bir Belirtecin Ömrü
Dogrulayici.gecerliMi yalnız iki şeye bakıyor: belirtecin kendi gecerlilikSonu alanına
ve kendisine verilen suAn değerine. Bu, dersin en sınırlayıcı ölçümünü doğuruyor: bir
belirteç “iptal edilse” bile, doğrulayıcının bakacağı hiçbir iptal listesi yoksa, iptal
kaydı belirtecin geçerliliğini hiç etkilemiyor. Uygulama kendi tarafında bir iptal listesi
tutabilir, ama gecerliMi bu listeye hiç erişmiyor — erişseydi, durumsuz olmaktan çıkar,
her çağrıda paylaşılan bir yapıya bakan bir doğrulayıcıya dönerdi.
// IptalVeGecerlilik.java — iptal edilen belirtec, dogrulayici iptal listesine hic bakmadigi icin suresi dolana kadar gecerli sayilmaya devam ediyor
import java.util.*;
public class IptalVeGecerlilik {
public static void main(String[] args) {
Belirtec belirtec = new Belirtec("kullanici-9", Map.of("rol", "calisan"), 10);
Set<String> iptalEdilenler = new HashSet<>();
Dogrulayici.goster("iptalden once, an=0, gecerli mi", Dogrulayici.gecerliMi(belirtec, 0));
iptalEdilenler.add(belirtec.konu());
Dogrulayici.goster("konu iptal listesinde mi", iptalEdilenler.contains(belirtec.konu()));
int gecerliKalanAdim = 0;
for (int an = 1; an <= 15; an++) {
if (Dogrulayici.gecerliMi(belirtec, an)) gecerliKalanAdim++;
}
Dogrulayici.goster("iptalden sonra dogrulayicinin gecerli saydigi adim sayisi", gecerliKalanAdim);
Dogrulayici.goster("an=11, gecerli mi (sure doldu)", Dogrulayici.gecerliMi(belirtec, 11));
}
}
iptalden once, an=0, gecerli mi : true konu iptal listesinde mi : true iptalden sonra dogrulayicinin gecerli saydigi adim sayisi: 10 an=11, gecerli mi (sure doldu) : false
iptalEdilenler kümesi belirtec.konu()’yu tutuyor — uygulama bu konuyla ilgili bir karar
verdi. Ama Dogrulayici.gecerliMi bu kümenin varlığından habersiz; ona hiç parametre olarak
verilmiyor, hiç sorgulanmıyor. GT10. Durumsuz doğrulama yalnız belirtecin kendi
alanlarına ve verilen adıma bakar; iptal listesi gibi paylaşılan bir duruma erişimi yoktur.
GT11. İptal edilmiş bir belirteç, doğrulayıcı iptal listesine hiç bakmadığı için süresi
dolana kadar geçerli sayılmaya devam eder — bu derste bu süre on adım, ve on birinci adımda
gecerlilikSonu aşıldığı için doğrulama kendiliğinden false dönüyor. On adımlık bu pencere
belirtecin kendi gecerlilikSonu değerinden geliyor; kısa tutulan bir geçerlilik süresi bu
pencereyi daraltır, ama sıfıra indirmez. Bunu iddia olarak bırakmadan koşturarak doğrulamak
için aynı ölçüm daha kısa bir geçerlilik süresiyle tekrarlanıyor.
// KisaPencere.java — gecerlilik suresi kisaltilinca, iptalden sonra gecerli sayilan adim sayisi da ayni oranda kisaliyor
import java.util.*;
public class KisaPencere {
public static void main(String[] args) {
Belirtec kisaOmurlu = new Belirtec("kullanici-11", Map.of("rol", "calisan"), 3);
int gecerliKalanAdim = 0;
for (int an = 1; an <= 15; an++) {
if (Dogrulayici.gecerliMi(kisaOmurlu, an)) gecerliKalanAdim++;
}
Dogrulayici.goster("gecerlilikSonu=3 belirtec, iptalden sonra gecerli sayilan adim", gecerliKalanAdim);
}
}
gecerlilikSonu=3 belirtec, iptalden sonra gecerli sayilan adim: 3
gecerlilikSonu on yerine üç verildiğinde, iptalden sonra geçerli sayılan adım sayısı da on
yerine üç oluyor — pencere daralıyor, orantılı biçimde. Ama sıfıra hiç inmiyor, çünkü
gecerliMi çağrısının kendisi hâlâ yalnız bir sayı karşılaştırması; iptali anında görebilmesi
için doğrulayıcının paylaşılan bir duruma bakması gerekirdi, ve o bakışı eklemek onu artık
durumsuz olmaktan çıkarırdı. Bu, dersin sınırlayıcı ölçümü: durumsuzluk bedelsiz değil, bedeli
iptalin gecikmesiyle ölçülüyor, ve bu gecikme — geçerlilik süresi kısaltıldıkça küçülse de —
hiçbir zaman sıfır olmuyor.
Dersin üç ölçümü yan yana konduğunda aynı örüntü tekrar ediyor: kaynakta duran ya da hiç durmayan bir bilgi, ancak koşturularak sayıya dönüşüyor.
| Ölçüm | Bu derste gözlenen |
|---|---|
| iddia sayısı (misafir / yönetici) | 1 / 3 |
| doğrulama kaynağı (açıklama / çağrı) | ikisi de aynı sonucu üretiyor |
| iptalden sonra geçerli kalan adım (geçerlilik süresi 10) | 10 |
| iptalden sonra geçerli kalan adım (geçerlilik süresi 3) | 3 |
Son iki satır aynı düzeneği iki ayrı parametreyle koşturuyor ve bedelin sabit değil, geçerlilik süresiyle orantılı olduğunu gösteriyor — bu da kaynakta yazılı bir sayı değil, iki koşumun karşılaştırılmasıyla ortaya çıkan bir ilişki.
Özet
- Belirteç, sunucu tarafında hiçbir oturum kaydı tutulmadan kimliğe dair bilgiyi kendi iddiaları içinde taşır; taşınan iddia sayısı belirteçten belirtece değişir.
- Bir yetki sorusu bir açıklamadan (
@GerekliIddia) okunarak yanıtlanabilir; karar kaynakta hiçbir çağrı ifadesi doğurmaz. - Aynı soru kaynakta yazılı bir karşılaştırmadan (çağrıdan) da yanıtlanabilir; iki kaynak aynı sonucu üretir, farklı yerden.
- Durumsuz doğrulama yalnız belirtecin kendi alanlarına ve verilen ana bakar; paylaşılan hiçbir duruma (iptal listesi gibi) erişimi yoktur.
- İptal edilmiş bir belirteç, doğrulayıcı iptal listesine hiç bakmadığı için süresi dolana kadar geçerli sayılmaya devam eder; bu, kaç adım sürdüğü sayılabilen bir bedeldir.
Sonraki Adım
Bu iki ders yetkilendirme kararının kaynağını tek bir çağrı ya da tek bir belirteç üzerinden ölçtü. Bir kabın gerçekte kaç bileşeni ayağa kaldırdığı, hangi testin hangi parçayı kurduğu henüz hiç sorulmadı. Sıradaki ders aynı kabı bir test ortamına koyuyor ve iki kurulumu yan yana sayıyor: dilim testi kaç bileşeni ayağa kaldırıyor, tam bağlam testi kaç bileşeni — ve dilimin dışında kalan bir açıklamaya ne oluyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.