Ders 21 / 23
Kapsamlar ve İzinler
Belirteç kapsamının sahibinin yetkisinden dar tutulması, kapsam ve izin katmanlarının kesişimiyle verilen karar, reddin nedenine göre ayrışan yanıtlar, erişim yüzeyinin ölçülmesi ve yenilemede daraltma kuralı.
İçindekiler
Önceki dört ders kararı kişiye bağladı: kim hangi rolde, hangi özniteliklere sahip, nesneyle nasıl bir ilişkisi var. Bu soruların yanıtı bir kişi için sabittir. Ancak isteği yapan çoğu zaman kişinin kendisi değildir: kütüphanenin mobil uygulaması, bir rapor aracı, kişinin yetkilendirdiği üçüncü taraf bir okuma listesi servisi.
Bu istemcilere kişinin bütün yetkisini vermek gereksizdir. Okuma listesi servisinin ödünç kaydı silmeye ihtiyacı yoktur; rapor aracının üye adresini okumaya ihtiyacı yoktur. Kapsam (scope), bir belirtecin taşıdığı yetkinin, sahibinin yetkisinden daha dar olmasını sağlayan mekanizmadır.
İki Katmanlı Karar
Kapsam, önceki derslerdeki yetki modellerinin yerine geçmez; üstüne biner. Bir istek iki soruyu birden geçmek zorundadır: kişi bunu yapabilir mi ve bu istemciye bu yetki verilmiş mi. İkisi ayrı kaynaklardan gelir — birincisi kullanıcı yönetiminden, ikincisi belirtecin verildiği andaki onaydan.
Karar bu yüzden bir kesişimdir. Kapsam yetkiyi genişletemez: bir belirteçte ceza:yaz
kapsamı bulunması, sahibinin ceza tahsil etme izni yoksa hiçbir şey ifade etmez. Tersi de
geçerlidir: yetkili bir görevlinin belirteci, kapsamı dışındaki uç noktaya erişemez.
Aşağıdaki hesap bu iki katmanı bir eşleme tablosu üzerinde çalıştırır.
cat > kapsam.mjs <<'EOF' // kapsam.mjs — belirtec kapsamlarinin uc noktalara eslenmesi ve iki katmanli karar // 1. Uc nokta -> gereken kapsam eslemesi. Sozlesmenin parcasidir. const UC_NOKTALAR = [ { yontem: "GET", yol: "/oduncler", kapsam: "odunc:oku" }, { yontem: "POST", yol: "/oduncler", kapsam: "odunc:yaz" }, { yontem: "DELETE", yol: "/oduncler/{id}", kapsam: "odunc:yaz" }, { yontem: "GET", yol: "/uyeler/{id}", kapsam: "uye:oku" }, { yontem: "PATCH", yol: "/uyeler/{id}", kapsam: "uye:yaz" }, { yontem: "GET", yol: "/uyeler/{id}/cezalar", kapsam: "ceza:oku" }, { yontem: "POST", yol: "/cezalar/{id}/tahsil", kapsam: "ceza:yaz" }, { yontem: "GET", yol: "/raporlar/gecikme", kapsam: "rapor:oku" }, ]; // 2. Ozne izinleri (RBAC dersinden): kisinin yapabildikleri. const IZINLER = { "U-1001": new Set(["odunc:oku", "odunc:yaz", "uye:oku", "ceza:oku"]), "P-2001": new Set(["odunc:oku", "odunc:yaz", "uye:oku", "uye:yaz", "ceza:oku", "ceza:yaz"]), "Y-3001": new Set(["odunc:oku", "odunc:yaz", "uye:oku", "uye:yaz", "ceza:oku", "ceza:yaz", "rapor:oku"]), }; // 3. Belirtecler: istemciye verilen kapsam kumesi. Kisinin izinleriyle ayni sey degildir. const BELIRTECLER = [ { ad: "mobil-uygulama", ozne: "U-1001", kapsamlar: ["odunc:oku", "odunc:yaz", "uye:oku"] }, { ad: "okuma-listesi", ozne: "U-1001", kapsamlar: ["odunc:oku"] }, { ad: "rapor-araci", ozne: "P-2001", kapsamlar: ["rapor:oku", "odunc:oku"] }, { ad: "banko-uygulamasi", ozne: "Y-3001", kapsamlar: ["odunc:oku", "odunc:yaz", "uye:yaz", "ceza:yaz"] }, ]; // 4. Karar: iki katman da gecmeli. Kapsam istemcinin yetkisini, izin kisinin yetkisini sinirlar. function karar(belirtec, uc) { const kapsamVar = belirtec.kapsamlar.includes(uc.kapsam); const izinVar = IZINLER[belirtec.ozne].has(uc.kapsam); if (!kapsamVar && !izinVar) return "red: kapsam ve izin yok"; if (!kapsamVar) return "red: belirtecin kapsami yok"; if (!izinVar) return "red: oznenin izni yok"; return "izin"; } const dolgu = (s, n) => String(s).padEnd(n); console.log("belirtec uc nokta sonuc"); for (const b of BELIRTECLER) { for (const uc of UC_NOKTALAR) { const s = karar(b, uc); if (s === "izin") continue; // yalniz reddedilenleri goster if (!IZINLER[b.ozne].has(uc.kapsam) && !b.kapsamlar.includes(uc.kapsam)) continue; console.log(`${dolgu(b.ad, 18)} ${dolgu(uc.yontem + " " + uc.yol, 33)} ${s}`); } } // 5. Kapsamin erisim yuzeyi: her belirtec kac uc noktaya ulasabiliyor? console.log("\nbelirtec kapsam izinli uc nokta yuzey"); for (const b of BELIRTECLER) { const izinli = UC_NOKTALAR.filter((uc) => karar(b, uc) === "izin"); const yuzde = ((100 * izinli.length) / UC_NOKTALAR.length).toFixed(0); console.log(`${dolgu(b.ad, 18)} ${dolgu(b.kapsamlar.length, 7)} ${dolgu(izinli.length + " / " + UC_NOKTALAR.length, 16)} %${yuzde}`); } // 6. Kapsam taneciginin etkisi: kaba kapsam ile ince kapsamin yuzeyi. const KABA = ["odunc:*", "uye:*"]; const kabaEsler = (uc) => KABA.some((k) => uc.kapsam.startsWith(k.slice(0, -1))); const kabaYuzey = UC_NOKTALAR.filter(kabaEsler).length; const inceYuzey = UC_NOKTALAR.filter((uc) => ["odunc:oku", "uye:oku"].includes(uc.kapsam)).length; console.log(`\nkaba kapsam ${JSON.stringify(KABA)} -> ${kabaYuzey} / ${UC_NOKTALAR.length} uc nokta`); console.log(`ince kapsam ["odunc:oku","uye:oku"] -> ${inceYuzey} / ${UC_NOKTALAR.length} uc nokta`); console.log(`okuma isteyen bir istemciye kaba kapsam verilirse fazladan ${kabaYuzey - inceYuzey} uc nokta acilir.`); // 7. Yenilemede daraltma: istemci daha az kapsam isteyebilir, daha cogunu isteyemez. function yenile(belirtec, istenen) { const disarida = istenen.filter((k) => !belirtec.kapsamlar.includes(k)); return disarida.length ? { sonuc: "red", neden: "istenen kapsam ilk belirtecin disinda: " + disarida.join(", ") } : { sonuc: "kabul", kapsamlar: istenen }; } const mobil = BELIRTECLER[0]; console.log("\nyenileme denemeleri (ilk kapsam: " + JSON.stringify(mobil.kapsamlar) + ")"); for (const istenen of [["odunc:oku"], ["odunc:oku", "uye:oku"], ["odunc:oku", "ceza:yaz"]]) { const y = yenile(mobil, istenen); console.log(` ${dolgu(JSON.stringify(istenen), 34)} ${y.sonuc}${y.neden ? " — " + y.neden : ""}`); } EOF node kapsam.mjs
belirtec uc nokta sonuc
mobil-uygulama GET /uyeler/{id}/cezalar red: belirtecin kapsami yok
okuma-listesi POST /oduncler red: belirtecin kapsami yok
okuma-listesi DELETE /oduncler/{id} red: belirtecin kapsami yok
okuma-listesi GET /uyeler/{id} red: belirtecin kapsami yok
okuma-listesi GET /uyeler/{id}/cezalar red: belirtecin kapsami yok
rapor-araci POST /oduncler red: belirtecin kapsami yok
rapor-araci DELETE /oduncler/{id} red: belirtecin kapsami yok
rapor-araci GET /uyeler/{id} red: belirtecin kapsami yok
rapor-araci PATCH /uyeler/{id} red: belirtecin kapsami yok
rapor-araci GET /uyeler/{id}/cezalar red: belirtecin kapsami yok
rapor-araci POST /cezalar/{id}/tahsil red: belirtecin kapsami yok
rapor-araci GET /raporlar/gecikme red: oznenin izni yok
banko-uygulamasi GET /uyeler/{id} red: belirtecin kapsami yok
banko-uygulamasi GET /uyeler/{id}/cezalar red: belirtecin kapsami yok
banko-uygulamasi GET /raporlar/gecikme red: belirtecin kapsami yok
belirtec kapsam izinli uc nokta yuzey
mobil-uygulama 3 4 / 8 %50
okuma-listesi 1 1 / 8 %13
rapor-araci 2 1 / 8 %13
banko-uygulamasi 4 5 / 8 %63
kaba kapsam ["odunc:*","uye:*"] -> 5 / 8 uc nokta
ince kapsam ["odunc:oku","uye:oku"] -> 2 / 8 uc nokta
okuma isteyen bir istemciye kaba kapsam verilirse fazladan 3 uc nokta acilir.
yenileme denemeleri (ilk kapsam: ["odunc:oku","odunc:yaz","uye:oku"])
["odunc:oku"] kabul
["odunc:oku","uye:oku"] kabul
["odunc:oku","ceza:yaz"] red — istenen kapsam ilk belirtecin disinda: ceza:yaz
Reddin Nedeni Ayırt Edilebilir Olmalı
Çıktının ilk bölümü reddedilen istekleri nedenleriyle listeliyor. İki neden birbirinden ayrıdır ve bu ayrım geliştiriciye farklı şey söyler.
“Belirtecin kapsamı yok” onarılabilir bir durumdur: istemci kullanıcıdan ek onay isteyip
daha geniş kapsamlı bir belirteç alabilir. “Öznenin izni yok” ise onarılamaz; hiçbir onay
akışı görevliye rapor okuma izni veremez, çünkü o izin kullanıcı yönetiminde tanımlıdır.
Rapor aracı satırı bunun örneğidir: belirteçte rapor:oku kapsamı vardır ama öznenin izni
yoktur, dolayısıyla istek reddedilir.
İstemciye dönen yanıt bu ayrımı taşımalıdır. Yetersiz kapsam için standart, hangi kapsamın gerektiğini bildiren bir yanıttır; yetersiz izin için ise ek bilgi verilmez — kullanıcının neye yetkili olmadığını ayrıntılandırmak, yetki haritasını dışarıya sızdırır.
Kapsam Bir Erişim Yüzeyidir
İkinci bölüm her belirtecin kaç uç noktaya ulaşabildiğini sayıyor. Bu sayı, belirteç sızdığında ne kadar zarar verilebileceğinin doğrudan ölçüsüdür: okuma listesi servisinin belirteci sekiz uç noktanın birine, banko uygulamasının belirteci beşine erişir.
Yüzeyin ölçülebilir olması bir tasarım aracıdır. Bir istemcinin istediği kapsam kümesi
onaylanmadan önce sorulacak soru şudur: bu kümenin açtığı uç nokta sayısı, istemcinin
gerçekten yaptığı işle orantılı mı? Okuma listesi servisi yalnız ödünç geçmişini okuyorsa
odunc:oku yeterlidir; odunc:yaz istemesi, yüzeyi üç katına çıkarır ve gerekçesi
yoktur.
Tanecik Boyutu Bir Karardır
Üçüncü bölüm kaba ve ince kapsamı karşılaştırıyor. Kaynak başına tek bir kapsam
tanımlamak — odunc:* gibi — kapsam listesini kısaltır ama okuma isteyen bir istemciye
yazma yetkisini de verir; modelde bu, fazladan üç uç nokta demektir.
Ters uçta her uç nokta için ayrı kapsam tanımlamak da işe yaramaz: kapsam listesi
büyüdükçe onay ekranı okunamaz hâle gelir ve kullanıcı listeyi okumadan onaylar. İşe
yarayan tanecik, kaynak ve eylem ikilisidir: odunc:oku, odunc:yaz. Bu düzeyde
kapsam sayısı kaynak sayısının iki katıdır ve her kapsamın karşılığı bir cümleyle
anlatılabilir.
Kapsam adının kendisi de sözleşmenin parçasıdır. Uç nokta değiştiğinde kapsam adı sabit kalır; kapsam adı değiştiğinde bütün istemcilerin yeniden onay alması gerekir. Bu, API Sürümleme dersindeki kırıcı değişiklik kuralının yetkilendirme tarafındaki karşılığıdır.
Yenilemede Daraltma Vardır, Genişletme Yoktur
Son bölüm yenileme davranışını gösteriyor. Bir istemci elindeki belirteci yenilerken daha dar bir kapsam kümesi isteyebilir; bu, uzun ömürlü bir oturumda geçici olarak daha az yetkiyle çalışmayı mümkün kılar. Daha geniş bir küme isteyemez: genişletme, yeni bir onay akışı gerektirir.
Kural tek cümleyle yazılır: yenilenen belirtecin kapsamı, ilk belirtecin kapsamının alt kümesi olmalıdır. Bu kuralın uygulanmaması, yenileme uç noktasını sessiz bir yetki yükseltme yoluna çevirir — çünkü yenileme, kullanıcı onayı olmadan çalışan bir akıştır.
Özet
- Kapsam, belirtecin yetkisini sahibinin yetkisinden daha dar tutar; karar iki katmanın kesişimidir ve kapsam hiçbir zaman yetkiyi genişletmez.
- Yetersiz kapsam ile yetersiz izin farklı yanıtlar üretir: birincisi hangi kapsamın gerektiğini bildirir, ikincisi ayrıntı vermez.
- Bir belirtecin eriştiği uç nokta sayısı, sızma durumundaki zararın ölçüsüdür; modelde belirteçlerin yüzeyi yüzde on üç ile yüzde altmış üç arasında değişiyor.
- Tanecik kaynak–eylem düzeyinde tutulur: kaba kapsam okuma isteyen istemciye üç fazladan uç nokta açar, aşırı ince kapsam onay ekranını okunamaz yapar.
- Yenilemede kapsam yalnız daraltılabilir; genişletme yeni onay gerektirir, aksi hâlde yenileme sessiz bir yetki yükseltme yoluna dönüşür.
Sonraki Adım
Buraya kadarki bütün kararlar tek bir kütüphanenin içinde verildi: bir üye, bir görevli, bir şube. Aynı sunucu birden çok kütüphaneye hizmet verdiğinde araya yeni bir sınır girer ve bu sınır rol ya da kapsamla değil veriyle çizilir: bir kütüphanenin görevlisi, kendi kurumunun kayıtlarını görebilmeli, komşu kurumunkileri hiçbir koşulda görememelidir. Sonraki ders bu yalıtımı ele alır ve sınırın sorgunun kendisine nasıl taşındığını gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.