---
title: 'Rol Tabanlı Erişim Denetimi'
source: 'https://academia.sh/tr/kurslar/kimlik-ve-yetki/rol-tabanli-erisim-denetimi'
course: 'Kimlik Doğrulama ve Yetkilendirme'
language: tr
updated: '2026-08-17T18:06:49+00:00'
license: 'CC BY-SA 4.0'
---

# Rol Tabanlı Erişim Denetimi

İzinlerin kişiye değil göreve bağlanması, rol devralmasının etkin izin kümesini nasıl gizlediği, ortak senaryo kümesinde rol tabanlı kararın nerede doğru nerede yanlış olduğu ve rol patlamasının ölçülmesi.

Önceki konu "karşımdaki kim" sorusuna verilen yanıtları kurdu. Oturum silme sorgusundaki
`AND uye = ?` koşulu ise ikinci soruyu açtı: kim olduğu bilinen birinin neyi yapabileceği.
Bu konu o soruyla ilgili ve dört ayrı modelle yanıtlıyor. Modeller birbirinin yerine geçmez;
her biri belirli bir kısıt türünü ifade edebilir, başka bir türü edemez.

Karşılaştırmanın anlamlı olması için dört model **aynı senaryo kümesini** değerlendirecek.
Küme kütüphane ödünç servisinden alınmış sekiz istekten oluşuyor ve her senaryonun bir de
doğru yanıtı var — kütüphanenin iş kuralının verdiği yanıt. Modellerin başarısı, kendi
kararlarının bu yanıtla uyuşmasıyla ölçülüyor.

## Rol, İzin ve Devralma

**Rol tabanlı erişim denetimi (role-based access control)**, izinleri kişilere değil
görevlere bağlar. Bu model İlişkisel Veritabanı Yönetimi kursunda veritabanı hesapları için
kurulmuştu; buradaki fark katmandır. Orada denetlenen şey bir bağlantının hangi tabloya
dokunabildiğiydi; burada denetlenen şey bir isteğin hangi işlemi yürütebildiğidir. İki
katman ayrı ayrı bulunur ve biri diğerinin yerine geçmez: uygulama katmanındaki denetim
atlanırsa veritabanı katmanı son savunmadır.

**İzin (permission)**, bir eylem ile bir kaynak türünün birleşimidir: `goruntule:odunc`,
`sil:ceza`. **Rol**, izinlerin adlandırılmış bir kümesidir. **Rol devralması (role
inheritance)** bir rolün başka bir rolün izinlerini kapsamasıdır; şube yöneticisi görevlinin
her şeyini yapabilsin diye görevli rolünü devralır.

Devralmanın bedeli şudur: bir rolün gerçek izin kümesi yazıldığı yerde görünmez, devralma
zincirinin kapanışı alınarak hesaplanır. Aşağıdaki betik bu kapanışı üretiyor ve ortak
senaryo kümesini değerlendiriyor.

```bash
cat > rbac.mjs <<'EOF'
const ROL_IZIN = {
  uye:             ["goruntule:odunc", "goruntule:liste"],
  gorevli:         ["guncelle:odunc", "olustur:odunc"],
  sube_yoneticisi: ["sil:ceza", "sil:odunc"],
};
const ROL_DEVRAL = { uye: [], gorevli: ["uye"], sube_yoneticisi: ["gorevli"] };
const OZNE_ROL = {
  "U-1001": ["uye"], "U-1002": ["uye"], "U-1005": ["uye"],
  "P-2001": ["gorevli"], "Y-3001": ["sube_yoneticisi"],
};

// Ortak senaryo kumesi: bu konudaki dort model ayni kumeyi degerlendirir.
// [ad, ozne, eylem, nesne, nesne ozellikleri, saat, dogru yanit]
const SENARYOLAR = [
  ["S1", "U-1001", "goruntule", "odunc:501",  { sahip: "U-1001", sube: "S-02" }, "10:15", true],
  ["S2", "U-1001", "goruntule", "odunc:502",  { sahip: "U-1002", sube: "S-02" }, "10:16", false],
  ["S3", "P-2001", "goruntule", "odunc:502",  { sahip: "U-1002", sube: "S-02" }, "10:20", true],
  ["S4", "P-2001", "goruntule", "odunc:503",  { sahip: "U-1005", sube: "S-01" }, "10:21", false],
  ["S5", "P-2001", "guncelle",  "odunc:502",  { sahip: "U-1002", sube: "S-02" }, "22:40", false],
  ["S6", "Y-3001", "sil",       "ceza:77",    { sahip: "U-1002", sube: "S-02" }, "11:05", true],
  ["S7", "U-1002", "goruntule", "liste:9",    { sahip: "U-1001", sube: "S-02" }, "12:00", true],
  ["S8", "U-1005", "goruntule", "liste:9",    { sahip: "U-1001", sube: "S-02" }, "12:01", false],
];

function etkinIzinler(rol, gorulen = new Set()) {
  if (gorulen.has(rol)) return new Set();          // devralma dongusune karsi
  gorulen.add(rol);
  const kume = new Set(ROL_IZIN[rol] ?? []);
  for (const ust of ROL_DEVRAL[rol] ?? []) {
    for (const izin of etkinIzinler(ust, gorulen)) kume.add(izin);
  }
  return kume;
}

const ozneIzinleri = (ozne) => {
  const k = new Set();
  for (const rol of OZNE_ROL[ozne] ?? []) for (const i of etkinIzinler(rol)) k.add(i);
  return k;
};

const rbac = (ozne, eylem, nesne) =>
  ozneIzinleri(ozne).has(`${eylem}:${nesne.split(":")[0]}`);

console.log("rol             | etkin izin kumesi");
console.log("----------------|-----------------------------------------------------");
for (const rol of Object.keys(ROL_IZIN)) {
  console.log(rol.padEnd(15) + " | " + [...etkinIzinler(rol)].sort().join(", "));
}

console.log("\nsenaryo | ozne   | eylem     | nesne      | RBAC   | dogru  | uyum");
console.log("--------|--------|-----------|------------|--------|--------|------");
let uyan = 0;
for (const [ad, ozne, eylem, nesne, , , dogru] of SENARYOLAR) {
  const karar = rbac(ozne, eylem, nesne);
  if (karar === dogru) uyan++;
  console.log(
    `${ad}      | ${ozne} | ${eylem.padEnd(9)} | ${nesne.padEnd(10)} | ` +
    `${(karar ? "izin" : "ret").padEnd(6)} | ${(dogru ? "izin" : "ret").padEnd(6)} | ` +
    (karar === dogru ? "+" : "-")
  );
}
console.log(`\nRBAC dogru karar: ${uyan}/${SENARYOLAR.length}`);
EOF
node rbac.mjs
```

```text
rol             | etkin izin kumesi
----------------|-----------------------------------------------------
uye             | goruntule:liste, goruntule:odunc
gorevli         | goruntule:liste, goruntule:odunc, guncelle:odunc, olustur:odunc
sube_yoneticisi | goruntule:liste, goruntule:odunc, guncelle:odunc, olustur:odunc, sil:ceza, sil:odunc

senaryo | ozne   | eylem     | nesne      | RBAC   | dogru  | uyum
--------|--------|-----------|------------|--------|--------|------
S1      | U-1001 | goruntule | odunc:501  | izin   | izin   | +
S2      | U-1001 | goruntule | odunc:502  | izin   | ret    | -
S3      | P-2001 | goruntule | odunc:502  | izin   | izin   | +
S4      | P-2001 | goruntule | odunc:503  | izin   | ret    | -
S5      | P-2001 | guncelle  | odunc:502  | izin   | ret    | -
S6      | Y-3001 | sil       | ceza:77    | izin   | izin   | +
S7      | U-1002 | goruntule | liste:9    | izin   | izin   | +
S8      | U-1005 | goruntule | liste:9    | izin   | ret    | -

RBAC dogru karar: 4/8
```

## Modelin Doğru ve Yanlış Kararları

Sekiz senaryonun dördünde karar doğru, dördünde yanlış. Yanlışların hepsi aynı yöndedir:
model gereğinden fazla izin veriyor. Bu yön rastlantı değildir ve modelin yapısından gelir.

S2 en açık olanıdır. U-1001 kendi ödünç kaydını görüntüleyebilir, ama başka bir üyenin
kaydını göremez. Rol tabanlı model bu ikisini ayırt edemez, çünkü kararı yalnız özne ve
kaynak *türü* üzerinden verir. `odunc:501` ile `odunc:502` aynı türdendir; hangisinin kime
ait olduğu modelin göremediği bir bilgidir.

S4 aynı sorunun personel tarafıdır. Görevli ödünç kayıtlarını görüntüleyebilir; hangi
şubenin kayıtlarını görüntüleyebileceği izin adında yazılı değildir.

S5 zamanla ilgilidir. Ödünç kaydının mesai saatleri dışında değiştirilmemesi bir iş
kuralıdır ve rol tabanlı modelde ifade edilecek bir yeri yoktur — izinler isteğin bağlamını
görmez.

S8, S7 ile birlikte okunmalıdır. İkisinde de model "izin" diyor; S7'de bu doğru, S8'de
yanlış. Doğru olanı da yanlış nedenle doğrudur: model, listenin U-1002 ile paylaşılmış olup
U-1005 ile paylaşılmamış olduğunu bilmiyor, yalnız her üyenin liste görüntüleyebildiğini
biliyor. Doğru kararın doğru nedenle verilmesi, sonraki iki dersin konusu.

Bu dörtlünün ortak adı vardır: rol tabanlı model **kaba taneli** bir modeldir. Kaynağın
türüne kadar iner, örneğine inemez.

## Rol Patlaması

Eksik ayrımları rol tabanlı model içinde çözmenin bir yolu vardır: eksik olan koşulu rolün
adına yazmak. Şube ayrımı için `gorevli_S01`, `gorevli_S02`; mesai ayrımı için bunların
mesai içi ve mesai dışı sürümleri. Bu yolun maliyeti hesaplanabilir.

```bash
cat > rol-patlamasi.mjs <<'EOF'
const boyutlar = [
  ["gorev", 4, "okuyucu, gorevli, katalogcu, sube yoneticisi"],
  ["sube", 12, "kutuphanenin sube sayisi"],
  ["mesai", 2, "mesai ici / mesai disi"],
  ["kayit sahipligi", 2, "kendi kaydi / baskasinin kaydi"],
];

console.log("eklenen kosul       | carpan | gereken rol sayisi | ornek");
console.log("--------------------|--------|--------------------|--------------------------------");
let rol = 1;
for (const [ad, carpan, ornek] of boyutlar) {
  rol *= carpan;
  console.log(ad.padEnd(19) + " | " + String(carpan).padStart(6) + " | " +
    String(rol).padStart(18) + " | " + ornek);
}
console.log(`\nrol adlarinin ornegi: gorevli_S02_mesai_ici_baskasinin_kaydi`);
console.log(`atama sayisi: her personel icin ${rol} rolden dogru olani secilir`);
EOF
node rol-patlamasi.mjs
```

```text
eklenen kosul       | carpan | gereken rol sayisi | ornek
--------------------|--------|--------------------|--------------------------------
gorev               |      4 |                  4 | okuyucu, gorevli, katalogcu, sube yoneticisi
sube                |     12 |                 48 | kutuphanenin sube sayisi
mesai               |      2 |                 96 | mesai ici / mesai disi
kayit sahipligi     |      2 |                192 | kendi kaydi / baskasinin kaydi

rol adlarinin ornegi: gorevli_S02_mesai_ici_baskasinin_kaydi
atama sayisi: her personel icin 192 rolden dogru olani secilir
```

Dört görev, bir şube eklendiğinde kırk sekiz role çıkıyor; iki koşul daha eklendiğinde yüz
doksan iki. Sayının kendisinden çok, büyüme biçimi önemlidir: her yeni koşul rol sayısını
**çarpar**. On üçüncü şube açıldığında on altı yeni rol tanımlanması gerekir ve bunların
her biri elle bakılan bir kayıttır.

İkinci maliyet okunabilirliktir. `gorevli_S02_mesai_ici_baskasinin_kaydi` adlı bir rolün ne
anlama geldiği adından çıkarılabilir, ama böyle yüz doksan iki adın arasında bir yanlışın
fark edilmesi çıkarılamaz. Bir personelin yanlış role atanması, yetki çizelgesine bakarak
görülemez hâle gelir.

Buradaki sınır rol tabanlı modelin kusuru değil, kapsamıdır. Model, görevin sabit olduğu ve
kararın isteğin bağlamına bağlı olmadığı durumlarda yalın ve denetlenebilirdir.

## Modelin Doğru Kullanıldığı Yer

Rol tabanlı modelin bırakılması gerekmiyor; sınırının bilinmesi gerekiyor. Sağlam kurulum
şu ayrımı yapar.

**Kaba taneli karar rolle verilir.** "Bu istek türü bu göreve açık mı?" sorusunun yanıtı
roldedir. Personel olmayan birinin ödünç kaydı güncelleme uç noktasına hiç ulaşmaması, rol
denetiminin işidir ve isteğin en başında yapılır.

**İnce taneli karar ayrı bir katmanda verilir.** "Bu belirli kayıt bu kişiye açık mı?"
sorusu, sonraki derslerin konusudur ve rolle değil, kaydın kendisiyle ilgilidir.

**Roller görevden türetilir, kişiden değil.** Bir role "şu kişi de erişebilsin" diye izin
eklemek, rolün adını yalanlar. Gerek varsa yeni bir rol tanımlanır.

**Rol atamaları düzenli denetlenir.** Bir kişinin taşıdığı etkin izin kümesi ile görevinin
gerektirdiği küme arasındaki fark ölçülür. Bu denetimin veritabanı tarafındaki karşılığı
İlişkisel Veritabanı Yönetimi kursunda kurulmuştu; uygulama tarafında da aynı yordam
uygulanır.

## Özet

- Rol tabanlı erişim denetimi izinleri göreve bağlar; izin, bir eylem ile bir kaynak
  türünün birleşimidir.
- Rol devralması etkin izin kümesini yazıldığı yerde görünmez kılar; küme, devralma
  zincirinin kapanışı alınarak hesaplanır.
- Model kaba tanelidir: kaynağın türüne iner, örneğine inemez. Ortak senaryo kümesinde
  sekiz karardan dördü yanlış çıkmıştır ve dördü de gereğinden fazla izin yönündedir.
- Eksik koşulları rol adına yazmak rol sayısını her koşulda çarpar; on iki şube ve iki
  koşul yüz doksan iki rol üretir.
- Rol tabanlı karar isteğin başında kaba taneli süzgeç olarak kalır; kayıt düzeyindeki
  karar ayrı bir katmanda verilir.

## Sonraki Adım

Yanlış çıkan dört kararın üçü aynı eksikten geliyor: model, isteğin bağlamını görmüyor.
Kaydın sahibi kim, personel hangi şubede çalışıyor, istek hangi saatte geldi — bunların
hepsi karar anında bilinen ama izin adında yeri olmayan bilgiler. Sonraki ders bu bilgileri
kararın girdisi hâline getiren öznitelik tabanlı erişim denetimini ele alıyor ve aynı sekiz
senaryoyu bu modelle yeniden değerlendiriyor.
