İçindekiler
Klasik ABAP'ta yetki kontrolü bir alışkanlıktır: program başında AUTHORITY-CHECK, gerekirse döngüde her satır için bir kontrol daha. Bu yöntem çalışır, ama kontrol programın içindedir. Aynı tabloyu okuyan ikinci bir program, bir OData servisi ya da bir rapor bu kontrolü unutursa veri açılır.
CDS access control (DCL, Data Control Language) yetkiyi veri modelinin yanına taşır: bir CDS varlığı için bir kez rol tanımlarsınız, o varlık ABAP SQL ile her okunduğunda kullanıcının yetkisine göre süzülür. Bu yazıda bu mekanizmayı, katmanlı görünümlerde ve RAP'ta nasıl kullanılacağını ve en önemlisi nerede devreye girmediğini anlatıyorum. Sözdizimi ve davranış SAP'nin ABAP anahtar kelime belgesine ve resmi ABAP cheat sheet deposuna dayanır; ayrıntılar sürüme göre değişebildiği için kendi sisteminizin belgesini de kontrol edin.
Neden Ayrı Bir Yetki Katmanı?
ABAP SQL ifadeleri veritabanında yetki kontrolü tetiklemez; bir SELECT, programı çalıştıran kullanıcı kim olursa olsun tablodaki bütün satırlara erişebilir. Bu yüzden yetki iki yoldan kontrol edilir:
| Konu | AUTHORITY-CHECK (açık) | CDS access control (örtük) |
|---|---|---|
| Nerede yazılır? | Programın içinde, her kullanım yerinde | CDS varlığı için bir kez, ayrı bir DCL nesnesinde |
| Ne zaman çalışır? | Geliştirici çağırdığında | Varlık ABAP SQL ile her okunduğunda |
| Sonuç | sy-subrc; karar programa kalır | Yetkisiz satırlar sonuçta yer almaz; hata dönmez |
| Kapsam | Her işlem (oluşturma, değiştirme, silme, aksiyon) | Yalnız okuma |
Son satır önemli: DCL bir okuma filtresidir. Kullanıcının bir kaydı değiştirip değiştiremeyeceğini söylemez. Bu yüzden iki yöntem birbirinin yerine geçmez, birlikte kullanılır.
@AccessControl.authorizationCheck
Her CDS varlığı, kendisi için bir rol beklenip beklenmediğini bu anotasyonla söyler:
| Değer | Anlamı |
|---|---|
#CHECK | Rol beklenir; yoksa etkinleştirmede uyarı verilir. Rol varsa uygulanır. |
#MANDATORY | Rol zorunludur; varlık için bir DCL nesnesi bulunmalıdır. |
#NOT_REQUIRED | Erişim kontrolünün gerekmediğini söyler; rol yoksa uyarı verilmez. |
#NOT_ALLOWED | Rol tanımlanmamalıdır; tanımlansa bile dikkate alınmaz. |
Benim önerim: kullanıcıya veya dış sisteme açılan her varlıkta #CHECK (ya da kuralı sertleştirmek için #MANDATORY) kullanın ve uyarıyı yok saymayın. #NOT_REQUIRED'ı ülke, birim, durum metni gibi gerçekten herkese açık veriler için saklayın. Bir varlıkta #NOT_REQUIRED görmek, kod incelemesinde "bu veri neden herkese açık?" sorusunu sordurmalıdır.
İlk Rol: pfcg_auth ile Şirket Kodu
Örnek olarak bir masraf formu tablosu düşünelim: her formun bir şirket kodu ve masraf yeri var. Kullanıcı yalnız yetkili olduğu şirket kodlarındaki formları görmeli. Yetki, şirket kodu (BUKRS) ve faaliyet (ACTVT) alanlarından oluşan kendi yetki nesnemizde tutuluyor: ZEXP_BUKRS.
Adım 1 — Rol bekleyen görünüm
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Masraf formu'
define view entity ZI_ExpenseReport
as select from zexp_report
{
key report_uuid as ReportUUID,
report_id as ReportID,
company_code as CompanyCode,
cost_center as CostCenter,
created_by as CreatedBy,
status as Status,
@Semantics.amount.currencyCode: 'Currency'
total_amount as TotalAmount,
currency as Currency
}Etkinleştirdiğinizde, henüz rol olmadığı için bir uyarı görürsünüz. Bu uyarı tam istediğimiz şeydir: varlık rol beklediğini söylüyor.
Adım 2 — DCL nesnesi (rol)
@EndUserText.label: 'Masraf formu: şirket kodu yetkisi'
@MappingRole: true
define role ZI_ExpenseReport {
grant select on ZI_ExpenseReport
where ( CompanyCode ) = aspect pfcg_auth( ZEXP_BUKRS, BUKRS, ACTVT = '03' );
}Bu rolün söylediği şey: "ZI_ExpenseReport okunurken yalnız, kullanıcının ZEXP_BUKRS nesnesinde ACTVT = '03' (görüntüleme) içeren yetkilerindeki BUKRS değerlerine uyan satırları getir." Rol etkinleştikten sonra görünümdeki uyarı kaybolur.
Belgede tanımlanan birkaç kural, rolün davranışını anlamak için önemlidir:
- Eşleme sırayla yapılır. Soldaki eleman sayısı, sağdaki yetki alanı sayısıyla aynı olmalıdır:
( CompanyCode, CostCenter ) = aspect pfcg_auth( ZEXP_AUTH, BUKRS, KOSTL, ACTVT = '03' ). - Sabit değerler süzgeçtir.
ACTVT = '03'yazdığınızda yalnız bu değeri içeren yetkiler hesaba katılır. - Birden çok yetki "veya" ile birleşir. Kullanıcının iki ayrı yetkisi varsa (biri 1000, öteki 2000 şirket kodu için), iki koşul
ORile bağlanır. - Tam yetki koşul üretmez. Bir alanda tam yetki (
*) varsa o alan için koşul oluşmaz; bu durumda boş (null) değerler de kabul edilir. - Yetki hiç yoksa koşul sağlanmaz. Kullanıcı hiçbir satır görmez.
On-premise sistemlerde yetki nesnesi PFCG rolleriyle kullanıcıya verilir. ABAP Cloud'da (BTP ABAP ortamı, S/4HANA Cloud) aynı yetki nesnesi bir IAM uygulamasına, oradan iş kataloğuna ve iş rolüne bağlanır. DCL tarafındaki rol iki dünyada da aynıdır; değişen yalnız yetkinin kullanıcıya nasıl ulaştığıdır.
Koşul Türleri ve ?= Operatörü
Bir erişim koşulu yalnız pfcg_auth'tan oluşmak zorunda değildir. Koşullar and / or ile birleştirilebilir:
- Literal koşul: bir elemanı sabit bir değerle karşılaştırır (
Status <> 'X'). - PFCG koşulu: yukarıdaki
aspect pfcg_auth. - Kullanıcı koşulu: elemanı oturum açmış kullanıcının adıyla karşılaştırır (
CreatedBy = aspect user). İzin verilen operatörler=,<>ve?='dir. - Kalıtım koşulu: başka bir varlığın koşullarını devralır (aşağıda).
true/false: her zaman sağlanan ya da hiç sağlanmayan koşul.
Örneğin "şirket kodu yetkisi olan herkes onaylanmış formları görsün, kendi formunu ise her durumda görsün" kuralı şöyle yazılabilir:
@EndUserText.label: 'Masraf formu: şirket kodu veya kendi formu'
@MappingRole: true
define role ZI_ExpenseReport {
grant select on ZI_ExpenseReport
where ( ( CompanyCode ) = aspect pfcg_auth( ZEXP_BUKRS, BUKRS, ACTVT = '03' )
and Status = 'A' )
or CreatedBy = aspect user;
}?= operatörü: bilerek kullanın
= yerine ?= yazıldığında koşul, soldaki bütün elemanlar null olduğunda da sağlanır, ve belgeye göre bu, kullanıcının hiç yetkisi olmasa bile geçerlidir. İsteğe bağlı bir ilişkiden (ör. henüz atanmamış bir masraf yeri) gelen alanlarda satırın tamamen kaybolmaması için tasarlanmıştır. Ama yan etkisi açıktır: alanı boş olan satırlar herkese görünür. ?='yi bir alışkanlık olarak değil, "bu alan boşsa satır herkese açık olabilir" kararını verdikten sonra kullanın.
Katmanlı Görünümler ve Kalıtım
DCL'yi yeni kullananların en sık atladığı kural şudur: yalnız ABAP SQL'de doğrudan okunan varlığın rolü değerlendirilir. Bir görünüm başka bir görünümden okuyorsa, alttaki görünümün rolü otomatik olarak uygulanmaz.
Tipik bir RAP veya Fiori yığınında bu şu anlama gelir: ZI_ExpenseReport için rol yazdınız, ama Fiori uygulaması ZC_ExpenseReport projeksiyonunu okuyor. Projeksiyonun kendi rolü yoksa, alttaki rol okunan veriyi süzmez. Her katmana aynı koşulu kopyalamak yerine kalıtım kullanın:
@EndUserText.label: 'Masraf formu projeksiyonu'
@MappingRole: true
define role ZC_ExpenseReport {
grant select on ZC_ExpenseReport
where inheriting conditions from entity ZI_ExpenseReport;
}Kalıtım, alttaki varlığın koşullarını bu varlığa uygular; alt rol değişince üst katman da değişir. Belgede yer alan birkaç ayrıntı:
- Devralınan varlığın henüz hiç koşulu yoksa
default trueya dadefault falseeklemek zorunludur; yoksa sözdizimi hatası alırsınız. replacing { ... }ile devralınan koşulda değişiklik yapılabilir. Örneğinpfcg_filter field ACTVT value '03' with '02'devralınan görüntüleme koşulunu değiştirme faaliyetine çevirir; alan adları farklıysaelement ... with ...(yalnız transactional projection görünümlerinde) ya da ilişki üzerindenroot with ...kullanılır.- Kalıtımın başına
notkonamaz ve döngüsel kalıtım sözdizimi hatasıdır. - Üst varlıktaki
@AccessControl.authorizationCheckanotasyonu kalıtımda dikkate alınmaz; koşullar yine devralınır.
Alt varlıklar: yol ifadesiyle koşul
Kalem tablosunda şirket kodu yoktur; kalem, başlığın şirket koduna göre görünmelidir. PFCG koşulunun solunda eleman yerine yol ifadesi yazılabilir:
@EndUserText.label: 'Masraf kalemi: başlığın şirket kodu'
@MappingRole: true
define role ZI_ExpenseItem {
grant select on ZI_ExpenseItem
where ( _Report.CompanyCode ) = aspect pfcg_auth( ZEXP_BUKRS, BUKRS, ACTVT = '03' );
}Kalem ve başlık için ayrı yetki mantığı kurmak yerine kalemi başlığa bağlamak, iki listenin birbirinden farklı sonuç göstermesini önler.
RAP: Okuma DCL'de, Değiştirme Davranışta
RAP'ta okuma işlemleri için CDS access control kullanılır ve managed senaryolarda otomatik uygulanır. Ama oluşturma, değiştirme, silme ve aksiyonlar için DCL hiçbir şey söylemez. Bunlar behavior definition'daki authorization master ile tanımlanır ve behavior pool'da AUTHORITY-CHECK ile uygulanır:
- Global yetki (
authorization master ( global )): kaydın durumundan bağımsız soru. "Bu kullanıcı hiç form silebilir mi?" Yetki yoksa istek, silme metoduna hiç ulaşmaz. - Instance yetkisi (
authorization master ( instance )): kaydın içeriğine bağlı soru. "Bu kullanıcı 1000 şirket kodundaki bu formu değiştirebilir mi?" - İkisi birlikte tanımlanabilir. Draft senaryolarında
Editaksiyonu güncelleme gibi ele alınır; onu da kontrol edin.
METHOD get_global_authorizations.
IF requested_authorizations-%delete = if_abap_behv=>mk-on.
AUTHORITY-CHECK OBJECT 'ZEXP_BUKRS'
ID 'BUKRS' DUMMY
ID 'ACTVT' FIELD '06'.
result-%delete = COND #( WHEN sy-subrc = 0
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized ).
ENDIF.
ENDMETHOD.Burada BUKRS DUMMY bilinçlidir: global yetki kaydın şirket kodunu bilmez, yalnız "bu kullanıcının herhangi bir şirket kodunda silme yetkisi var mı?" diye sorar. Hangi şirket kodunda silebileceği instance yetkisinin işidir. Tam bir draft ve yetki örneği için SAP RAP rehberine ve alt varlık yetkisini de içeren RAP proje örneğine bakabilirsiniz.
ACTVT = '03' ile şirket kodu süzüyor, instance yetkisinde ise başka bir yetki nesnesine bakıyorsanız, kullanıcı göremediği bir kaydı değiştirebilir ya da görebildiği bir kaydı açtığında anlaşılmaz bir hata alabilir. Aynı yetki nesnesini, farklı faaliyet değerleriyle kullanın.WITH PRIVILEGED ACCESS
Bazen bir programın kullanıcı yetkisinden bağımsız olarak bütün veriyi okuması gerekir: bütün şirket kodlarının toplamını hesaplayan bir arka plan işi ya da bir tutarlılık kontrolü gibi. ABAP SQL'de bunun için bir ek vardır:
SELECT CompanyCode, SUM( TotalAmount ) AS Total, Currency
FROM zi_expensereport WITH PRIVILEGED ACCESS
GROUP BY CompanyCode, Currency
INTO TABLE @DATA(totals).Belgeye göre bu ek, yazıldığı varlık için CDS access control'ü kapatır ve teslim edilen ya da sizin yazdığınız bütün rolleri geçersiz kılar. Sınırları:
- Yalnız yazıldığı varlığı etkiler; ilişkiler (association) üzerinden ulaşılan varlıklara yayılmaz.
- Yol ifadesiyle birlikte kullanılamaz.
- Veritabanı tablolarında ve klasik görünümlerde etkisizdir; zaten orada DCL yoktur.
Bu ekin her kullanımı, yetki sorumluluğunun DCL'den koda geçtiği bir yerdir. Kod incelemesinde WITH PRIVILEGED ACCESS araması yapmak ve her sonuç için "sonuç kime gösteriliyor?" diye sormak iyi bir alışkanlıktır. Ayrıcalıklı okunan veri bir kullanıcı ekranına gidiyorsa, büyük ihtimalle yanlış yerdesiniz.
DCL'nin Devreye Girmediği Yerler
DCL bir CDS varlığına bağlıdır ve ABAP SQL ile o varlık okunduğunda çalışır. Bunun dışındaki her yol, rolü atlar:
- Tablonun doğrudan okunması.
SELECT ... FROM zexp_reportDCL'yi tetiklemez; rol tabloya değil görünüme bağlıdır. Uygulama kodunda yetki gerektiren veriyi tablodan değil, rollü görünümden okuyun. - Rolü olmayan üst katman. Yukarıda anlatılan kural: alttaki görünümün rolü, üstteki görünüm okunurken uygulanmaz.
- AMDP ve Native SQL. SQLScript içinde okunan tablo ve görünümler için DCL değerlendirilmez. Bir CDS table function ise ABAP SQL ile okunduğunda kendi rolünü taşıyabilir. Ayrıntı için AMDP yazısına bakabilirsiniz.
- Tablo görüntüleme araçları. Tabloyu doğrudan gösteren araçlar CDS rolünü değil, kendi yetki kontrollerini uygular.
Rolü Nasıl Sınarım?
- ADT veri önizlemesi: Görünümde F8 ile açılan önizleme, oturumdaki kullanıcının yetkisiyle süzülmüş veriyi gösterir. Geliştirici kullanıcıların çoğunlukla geniş yetkisi olduğundan, kısıtlı rolü olan bir test kullanıcısıyla da açın.
- Karşılaştırmalı sayım: Bir test sınıfında aynı sorguyu normal ve
WITH PRIVILEGED ACCESSile çalıştırıp satır sayısını karşılaştırmak, rolün gerçekten süzdüğünü gösterir. - Sınır durumları: Hiç yetkisi olmayan kullanıcı, tam yetkili kullanıcı (
*), alanı boş satırlar (özellikle?=kullandıysanız) ve iki ayrı yetkisi olan kullanıcı. Bu dört durumu sınamadan rolü bitmiş saymayın. - Bütün katmanlar: Rolü yalnız arayüz görünümünde değil, uygulamanın gerçekten okuduğu projeksiyonda ve servis üzerinden de sınayın.
Sık Yapılan Hatalar
Rolü yalnız alt katmana yazmak
Fiori uygulaması projeksiyonu okur, rol arayüz görünümündedir; veri süzülmeden ekrana gelir. Her okunan katmana ya kendi koşulunu ya da inheriting conditions from entity ekleyin.
DCL'yi değiştirme yetkisi sanmak
DCL yalnız okumayı süzer. Değiştirme, silme ve aksiyonlar için RAP'ta global ve instance yetkisini ayrıca uygulayın.
#CHECK uyarısını yok saymak
"Rol yok" uyarısı, varlığın herkese açık olduğunu söyler. Uyarıyı kapatmak için #NOT_REQUIRED'a geçmek, sorunu gizler.
Uygulama kodunda tabloyu okumak
Rollü bir görünüm varken aynı veriyi tablodan okuyan bir yardımcı metot, rolü sessizce atlatır. Yetkili veriye tek kapıdan girin.
?='yi varsayılan yapmak
Alanı boş olan her satır herkese açılır. Yalnız boş değerin "herkes görebilir" anlamına geldiği alanlarda kullanın.
WITH PRIVILEGED ACCESS ile kullanıcıya veri göstermek
Bu ek teknik süreçler içindir. Sonucu bir kullanıcıya gidiyorsa, yetki kontrolünü kendiniz yapmadıkça veri sızdırıyorsunuz demektir.
Sonuç
CDS access control, yetkiyi "her programcı hatırlasın" sorumluluğundan çıkarıp veri modelinin bir parçası yapar. Ama yalnız kurulduğu yolda çalışır: ABAP SQL ile okunan, rolü olan varlıkta. Her okunan katmana rol (çoğu zaman kalıtım), değiştirme için RAP yetkisi, tablolara doğrudan erişimin ve ayrıcalıklı okumanın bilinçli olarak sınırlanması, bu modeli gerçekten güvenli yapan üç tamamlayıcıdır.
Clean core ve ABAP Cloud yaklaşımında yetkinin bu şekilde modellenmesi için ABAP Cloud ve clean core yazısına, sunduğum geliştirme kapsamı için SAP geliştirme hizmet sayfasına bakabilirsiniz.
CDS görünümlerinizin yetki modelini gözden geçirmek, DCL rollerini kurmak veya RAP uygulamanızda okuma ve yazma yetkisini birbirine bağlamak için destek alın.
Ön Görüşme Talep Et