📚 Qlik Sense Kurs – Artikel 25 von 28
← Vorheriger Artikel: Three-Stage Architecture
→ Nächster Artikel: Performance Tuning
Was ist Section Access? Das mächtigste Security-Feature in Qlik – Row & Column Level Security direkt im Script. User sehen nur IHRE Daten, automatisch gefiltert!
Section Access ist Qliks eingebautes Row-Level und Column-Level Security System, das Daten direkt im Arbeitsspeicher filtert, bevor der User sie sieht. Anders als normale Filter werden nicht-autorisierte Daten permanent aus dem RAM entfernt — der User kann die Einschränkung weder ändern noch umgehen.
In diesem Deep Dive Guide lernst du alles über Section Access: von der grundlegenden Architektur über System Fields (USERID, USER.EMAIL, OMIT, GROUP) bis zu fortgeschrittenen Patterns wie Composite Keys, Generic Keys und hierarchischer Security. Jedes Konzept enthält fertige Script-Beispiele zum Kopieren.
Voraussetzungen: Grundkenntnisse in Qlik Load Scripts und dem Star-Schema-Datenmodell.
KRITISCH: Section Access kann dich aus deiner eigenen App aussperren! IMMER einen ADMIN-Account mit BLANK Reduction anlegen, bevor du Section Access aktivierst!
Was ist Section Access in diesem vollständigen Deep Dive Guide?
- Wie funktioniert Qlik Section Access?
- Welche System Fields gibt es in Section Access?
- Wie implementiert man Row-Level Security in Qlik?
- Wie schützt man einzelne Spalten mit OMIT?
- Welche erweiterten Section Access Konzepte gibt es?
- Was sind die Unterschiede zwischen Cloud und On-Prem?
- Cheat Sheet: Copy & Paste Patterns
- Zusammenfassung & Nächste Schritte
Wie funktioniert die Architektur und die Grundlagen von Qlik Section Access?
Section Access filtert Daten auf RAM-Ebene, indem es eine Security-Tabelle gegen den authentifizierten User matched und alle nicht-autorisierten Rows permanent aus dem Arbeitsspeicher entfernt. Der Prozess läuft in 6 Schritten ab:
- Section Access lädt eine Security-Tabelle in den RAM
- User loggt sich in die App ein (über Proxy)
- Qlik matched den User gegen die Security-Tabelle
- Alle Reduction Fields werden als Selections angewendet
- Nicht-matchende Daten werden PERMANENT aus dem RAM entfernt
- User sieht nur noch «seine» Daten — keine Möglichkeit, andere zu sehen
Was ist der Unterschied zwischen Section Access und einem Filter?
Section Access ist kein Filter — es entfernt Daten komplett aus dem Speicher. Ein normaler Filter lässt die Daten im RAM und kann jederzeit geändert werden. Section Access dagegen ist permanent und unsichtbar.
| Aspekt | Normaler Filter | Section Access |
|---|---|---|
| Daten | Daten bleiben im RAM | Daten werden aus RAM entfernt |
| Änderbarkeit | User kann Filter ändern/löschen | Unmöglich zu ändern in Session |
| Performance | Alle Daten im Speicher | Nur User-Daten im Speicher |
| Security | Keine echte Security | Echte Security auf Daten-Ebene |
| Sichtbarkeit | Sichtbar in Selections Bar | Unsichtbar — User merkt es nicht |
Wie sieht die Section Access Script-Struktur aus?
Die Script-Struktur besteht aus zwei Abschnitten: Section Access für die Security-Tabelle und Section Application für den normalen App-Code. Alle Field Names und Values in Section Access werden automatisch zu UPPERCASE konvertiert.
// ===== SECTION ACCESS =====
// Dieser Teil lädt die Security-Tabelle
// ALLES hier wird UPPERCASE konvertiert — automatisch!
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION
ADMIN, ADMIN,
USER, DOMAINJOHNDOE, NORTH
];
// ===== SECTION APPLICATION =====
// Ab hier normaler App-Code
// Reduction Fields müssen hier auch UPPERCASE sein!
Section Application;
LOAD
Upper(Region) as REGION, // ← MUSS UPPERCASE sein für Match!
Sales,
Customer,
OrderDate
FROM [lib://Data/Sales.qvd] (qvd);
Gold Rule: ALLE Field Names und Field Values in Section Access werden automatisch zu UPPERCASE konvertiert. Deshalb MÜSSEN deine Reduction Fields in Section Application auch UPPERCASE sein!
Wie der Daten-Lade-Prozess grundsätzlich funktioniert, wird im ersten Kursartikel erklärt.
Was passiert Schritt für Schritt beim Login?
Beispiel: User DOMAINJOHNDOE loggt sich ein:
- Login: User authentifiziert sich am Qlik Server/Proxy
- Match: Qlik sucht
DOMAINJOHNDOEin Section Access Tabelle - Gefunden: USERID = DOMAINJOHNDOE, ACCESS = USER, REGION = NORTH
- Selection: Qlik macht automatisch Selection:
REGION = 'NORTH' - Reduction: Alle Rows mit REGION ≠ ‚NORTH‘ werden aus dem RAM gelöscht
- Result: User sieht nur Daten mit REGION = ‚NORTH‘
- Permanent: User kann diese «Selection» NICHT ändern oder clearen
Pro Tip: Section Access Security ist in der .qvf/.qvw File selbst gespeichert. Auch wenn User die App downloaded, bleibt Security aktiv!
Welche System Fields gibt es in Section Access?
Section Access kennt 7 System Fields, die steuern wer welche Daten sieht: ACCESS, USERID, USER.EMAIL, NTNAME, GROUP, OMIT und SERIAL. Jedes Field hat eine spezifische Aufgabe.
Was ist das ACCESS Field in Section Access und was sind die Unterschiede zwischen ADMIN und USER?
Das ACCESS Field ist Pflicht in jeder Section Access Tabelle und bestimmt die Berechtigungsstufe. Es hat genau 2 mögliche Werte: ADMIN und USER.
Section Access;
LOAD * INLINE [
ACCESS, USERID
ADMIN, ADMIN_USER // ← ADMIN Access
USER, NORMAL_USER // ← USER Access
];
Der entscheidende Unterschied: ADMIN sieht alle Daten wenn die Reduction fehlschlägt, USER bekommt «Access Denied».
| Eigenschaft | ADMIN | USER |
|---|---|---|
| Data Reduction | Optional (Fallback: alle Daten) | Immer erzwungen (Strict) |
| Reload App | Ja | Nein |
| Edit Script | Ja | Nein |
| Fehlende Reduction Values | Zeigt alle Daten | Access Denied |
| Strict Exclusion | Gilt NICHT | Gilt IMMER |
| OMIT Fields | Sieht alle Fields | Fields werden versteckt |
| Verwendung | Developer, Reload Accounts | Business User |
WICHTIG: ADMIN mit Data Reduction ist möglich, aber keine echte Security! Wenn Reduction fehlschlägt, sieht ADMIN trotzdem alle Daten. Für echte Security: Verwende USER Access Level!
Wie konfiguriert man USERID für On-Premise?
Das USERID Field identifiziert den User in Qlik Sense On-Premise über den Windows-Login im Format DOMAINUsername. Es muss exakt mit dem Windows-Login übereinstimmen.
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION
ADMIN, AD_DOMAINADMIN,
ADMIN, INTERNALSA_SCHEDULER, // ← Service Account für Reload!
USER, AD_DOMAINJOHNDOE, NORTH
USER, AD_DOMAINJANEDOE, SOUTH
];
USERID Format & Regeln:
- Format:
DOMAINUsername - Muss exakt mit Windows Login matchen
- Case-Insensitive: Wird automatisch UPPERCASE konvertiert
- Testing: Verwende
OSUser()Funktion in einem KPI um das Format zu prüfen - Wildcard:
*= alle authentifizierten User (mit Vorsicht verwenden!)
// Während Development: Erstelle KPI mit:
=OSUser()
// Output zeigt z.B.: AD_DOMAINJOHNDOE
// ← Genau so muss USERID in Section Access stehen!
Pro Tip: In Production Apps: Erstelle ein «Debug Sheet» (nur für Admins sichtbar) mit
OSUser(),OSName(),QlikAuthUser()etc. zum Troubleshooting! Mehr zu Error Handling Strategien.
Wie verwendet man USER.EMAIL in Qlik Cloud?
In Qlik Cloud ist USER.EMAIL das empfohlene Field zur User-Identifikation. Die Email-Adresse kommt vom Identity Provider (IdP) und ändert sich selten.
Section Access;
LOAD * INLINE [
ACCESS, USER.EMAIL, REGION
ADMIN, ADMIN@COMPANY.COM,
USER, JOHN.DOE@COMPANY.COM, NORTH
USER, JANE.DOE@COMPANY.COM, SOUTH
];
USER.EMAIL Details:
- Format: Standard Email-Adresse
- Source: Kommt von IdP (Identity Provider) Subject Claim
- Case: Case-insensitive (trotzdem
Upper()empfohlen) - Testing: Profil Icon → Settings zeigt Email
- Debug:
https://your-tenant.qlikcloud.com/api/v1/diagnose-claims
| Field | Vorteil | Nachteil |
|---|---|---|
| USER.EMAIL | Einfacher, Email ändert sich selten, Empfohlen von Qlik | Benötigt Email in Security DB |
| USERID | Funktioniert auch, für Migration nützlich | Komplexerer Setup, Subject Claim muss SAM account sein |
Best Practice Qlik Cloud: Verwende USER.EMAIL für neue Apps. Verwende USERID nur wenn du von On-Prem migrierst und die Security Table nicht ändern willst. Mehr dazu im Qlik Cloud Migration Guide.
Wann verwendet man NTNAME statt USERID?
NTNAME ist ein Legacy Field aus QlikView, das sowohl Windows Users als auch Active Directory Groups unterstützt. Das ist der entscheidende Unterschied zu USERID, das nur einzelne User matchen kann.
Section Access;
LOAD * INLINE [
ACCESS, NTNAME, REGION
ADMIN, AD_DOMAINADMIN,
USER, AD_DOMAINJOHNDOE, NORTH // ← Individual User
USER, AD_DOMAINSALES_TEAM, NORTH // ← AD Group!
USER, AD_DOMAINMANAGER_GROUP, * // ← Group sieht alle Regions
];
| Feature | NTNAME | USERID |
|---|---|---|
| Unterstützt Groups | Ja | Nein |
| Unterstützt Users | Ja | Ja |
| Empfohlen | Nur wenn Groups nötig | Wenn keine Groups |
| Performance | Langsamer (Group Resolution) | Schneller |
Wichtig: Verwende NICHT NTNAME + USERID in der gleichen Row! Sie matchen beide gegen die gleiche Authentication Info — das ist redundant und verwirrend.
Wie funktioniert das GROUP Field für Gruppenberechtigungen?
Das GROUP Field ist die moderne Methode um mit Gruppen zu arbeiten — sauberer und flexibler als NTNAME. Es ermöglicht eine klare Trennung zwischen User-Identifikation (USERID/USER.EMAIL) und Gruppenzugehörigkeit.
Section Access;
LOAD * INLINE [
ACCESS, USERID, GROUP, REGION
ADMIN, ADMIN, ,
ADMIN, INTERNALSA_SCHEDULER, ,
USER, *, SALES_EMEA, EMEA // ← Wildcard USERID + GROUP
USER, *, SALES_AMERICAS, AMERICAS
USER, AD_DOMAINSPECIAL_USER, , GLOBAL // ← Individual User
];
Section Application;
LOAD
Upper(Region) as REGION,
Sales,
Country
FROM Sales.qvd;
GROUP Field Vorteile:
- Saubere Trennung: Users in USERID/USER.EMAIL, Groups in GROUP
- Kombinierbar: User kann in GROUP sein UND individual USERID haben
- Wildcard Support:
USERID = *+GROUP = XYZ= «Alle User in Group XYZ» - Qlik Cloud Ready: Unterstützt IdP Groups UND Custom Groups
QlikCloudGroupMode in Qlik Cloud
In Qlik Cloud kannst du steuern welche Groups verwendet werden. Dies wird über eine SET Variable vor Section Access gesetzt:
// WICHTIG: VOR Section Access setzen!
// Modus 0: IdP Groups (Default - von Azure AD, Okta, etc.)
SET QlikCloudGroupMode = 0;
// Modus 1: Custom Groups (in Qlik Cloud Admin definiert)
SET QlikCloudGroupMode = 1;
// Modus 2: Beide (IdP + Custom Groups)
SET QlikCloudGroupMode = 2;
Section Access;
LOAD * INLINE [
ACCESS, USER.EMAIL, GROUP, REGION
USER, *, DATA_ANALYSTS, NORTH
USER, *, POWER_USERS, *
];
Wichtig für Qlik Cloud: QlikCloudGroupMode ist NICHT verfügbar in Qlik Sense Business oder wenn Qlik Identity Provider (IdP) verwendet wird. Nur in Qlik Sense Enterprise SaaS mit eigenem IdP! Mehr Details im Qlik Cloud Security Best Practices Artikel.
Wie versteckt man Spalten mit dem OMIT Field?
Das OMIT Field implementiert Column-Level Security — es versteckt komplette Spalten (Fields) vor bestimmten Users. Das Field existiert für den betroffenen User schlicht nicht, es ist nicht nur leer.
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION, OMIT
ADMIN, ADMIN, ,
USER, DOMAINMANAGER, NORTH, SALARY // ← Sieht kein SALARY Field
USER, DOMAINHR_USER, NORTH, // ← Sieht SALARY Field
];
Section Application;
LOAD
Upper(Region) as REGION,
EmployeeName,
Upper('Salary') as SALARY, // ← MUSS UPPERCASE sein!
Department
FROM HR.qvd;
OMIT Field Regeln:
- Field existiert NICHT für den User (nicht nur leer!)
- Nicht sichtbar im Data Model Viewer
- Charts mit diesem Field zeigen «Incomplete Visualization» Error
- Kann Wildcards verwenden:
COST*versteckt alle Fields die mit COST beginnen - Kann leer sein (keine Fields versteckt)
KRITISCH: Verwende OMIT NIEMALS auf Key Fields! Das führt zu Data Model Problemen und kann Synthetic Keys erzeugen. Key Fields sind im Data Model Viewer sichtbar aber leer — sehr verwirrend für User!
Was ist die Funktion des SERIAL Field in Cross-Platform Security?
Das SERIAL Field ermöglicht Cross-Platform Security Tables, die über QlikView, Qlik Sense On-Prem und Qlik Cloud hinweg funktionieren. Damit kannst du eine einzige Security-Tabelle für alle Plattformen pflegen.
Section Access;
LOAD * INLINE [
ACCESS, NTNAME, USER.EMAIL, SERIAL, REGION
// QlikView User
USER, AD_DOMAINJOHN, , 4600 0123 4567 8901, NORTH
// Qlik Sense On-Prem User
USER, AD_DOMAINJOHN, , QLIKSENSE, NORTH
// Qlik Cloud User
USER, , JOHN@COMPANY.COM, QLIKCLOUD, NORTH
// Admin für alle Platforms
ADMIN, ADMIN, ADMIN@COMPANY.COM, *, *
];
| SERIAL Value | Bedeutung | Platform |
|---|---|---|
* |
Alle Platforms | QlikView + Qlik Sense + Cloud |
QLIKVIEW |
Nur QlikView | QlikView |
QLIKSENSE |
Nur Qlik Sense | Qlik Sense On-Prem |
QLIKCLOUD |
Nur Qlik Cloud | Qlik Cloud |
License Number |
Specific QlikView License | QlikView (Legacy) |
Das SERIAL Field ist besonders nützlich bei einer Migration von QlikView zu Qlik Cloud.
Wie implementiert man Row-Level Security in Qlik?
Row-Level Security in Qlik wird über Reduction Fields in Section Access umgesetzt. Es gibt 5 Patterns — vom einfachen Single-Field bis zum komplexen Generic Keys Pattern. Welches Pattern du brauchst, hängt von der Komplexität deiner Berechtigungslogik ab.
Wie funktioniert Single-Field Reduction?
Single-Field Reduction ist das einfachste Pattern: Ein einziges Field (z.B. REGION) bestimmt, welche Daten der User sieht. Perfekt für einfache Szenarien wie «Sales Reps sehen nur ihre Region».
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION
ADMIN, ADMIN,
ADMIN, INTERNALSA_SCHEDULER, // ← KRITISCH für Reload!
USER, DOMAINJOHN_SALESREP, NORTH
USER, DOMAINJANE_SALESREP, SOUTH
USER, DOMAINMIKE_SALESREP, EAST
USER, DOMAINSALES_MANAGER, * // ← Sieht alle gelisteten Regions
];
Section Application;
Sales:
LOAD
*,
Upper(Region) as REGION // ← MUSS UPPERCASE sein!
FROM [lib://Data/Sales.qvd] (qvd);
Was passiert wenn DOMAINJOHN_SALESREP einloggt:
- Qlik matched: USERID = DOMAINJOHN_SALESREP → REGION = NORTH
- Selection wird automatisch gesetzt:
REGION = 'NORTH' - Alle Rows mit REGION ≠ ‚NORTH‘ werden aus RAM gelöscht
- App zeigt nur noch Sales für NORTH
- Selection ist unsichtbar und kann nicht geändert werden
Performance Vorteil — Section Access reduziert nicht nur den Zugriff, sondern auch den Speicherbedarf:
| Aspekt | Ohne Section Access | Mit Section Access |
|---|---|---|
| Rows im RAM | 1.000.000 Rows | 250.000 Rows (nur NORTH) |
| App Size | 500 MB | 125 MB |
| Load Time | 5 Sekunden | 1,5 Sekunden |
Mehr zur Performance-Optimierung in Qlik.
Wie filtert man nach mehreren Fields gleichzeitig?
Multiple Reduction Fields filtern nach mehreren Dimensionen gleichzeitig — z.B. Region UND Country. Aber Vorsicht: die Wildcard * bedeutet nicht «alle Werte im Datenmodell», sondern nur «alle in der Section Access Tabelle gelisteten Werte».
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION, COUNTRY
ADMIN, ADMIN, *, *
ADMIN, INTERNALSA_SCHEDULER, , // ← BLANK = alle Werte (nur ADMIN!)
USER, DOMAINMANAGER1, NORTH, USA
USER, DOMAINMANAGER2, SOUTH, UK
USER, DOMAINMANAGER3, NORTH, * // ← Alle gelisteten COUNTRIES
USER, DOMAINEXEC, *, * // ← Alle gelisteten REGIONS + COUNTRIES
];
Section Application;
Sales:
LOAD
*,
Upper(Region) as REGION,
Upper(Country) as COUNTRY
FROM [lib://Data/Sales.qvd] (qvd);
Das Wildcard-Problem erklärt
Das ist eine der häufigsten Fehlerquellen. Hier ein konkretes Beispiel:
// ===== SECTION ACCESS TABLE =====
// MANAGER3 hat: REGION = NORTH, COUNTRY = *
USERID, REGION, COUNTRY
MANAGER1, NORTH, USA
MANAGER2, SOUTH, UK
MANAGER3, NORTH, * // ← * = USA + UK (NICHT alle Countries!)
// ===== APP-DATEN =====
REGION, COUNTRY, Sales
NORTH, USA, 1000 // ← MANAGER3 sieht ✓
NORTH, UK, 500 // ← MANAGER3 sieht ✓
NORTH, GERMANY, 800 // ← MANAGER3 sieht NICHT ✗ (Germany nicht gelistet)
NORTH, FRANCE, 600 // ← MANAGER3 sieht NICHT ✗ (France nicht gelistet)
SOUTH, UK, 300 // ← MANAGER3 sieht NICHT ✗ (SOUTH ≠ NORTH)
Best Practice: Wenn du wirklich «alle Werte» brauchst, erstelle einen ADMIN User oder liste alle möglichen Werte explizit in Section Access!
Was ist das Composite Key Pattern und wann braucht man es?
Das Composite Key Pattern verhindert ungewollte Kreuzprodukte bei mehreren Reduction Fields. Es kombiniert alle Werte in einem einzigen Schlüssel und ist die empfohlene Lösung sobald du mehr als ein Reduction Field hast.
Das Problem mit separaten Fields
Wenn du einfach mehrere Reduction Fields verwendest, entstehen alle Kombinationen (Cartesian Product):
// FALSCH — Ungewollte Kombinationen
Section Access;
USERID, REGION, COUNTRY
JOHN, NORTH, USA
JOHN, SOUTH, UK
// Problem: JOHN sieht:
// NORTH + USA ✓ (gewollt)
// SOUTH + UK ✓ (gewollt)
// NORTH + UK ✗ (UNGEWOLLT — Cartesian Product!)
// SOUTH + USA ✗ (UNGEWOLLT — Cartesian Product!)
Die Lösung — ein kombinierter Key
Erstelle ein einzelnes ACCESS_KEY Field, das die exakte Kombination repräsentiert:
Section Access;
LOAD * INLINE [
ACCESS, USERID, ACCESS_KEY
ADMIN, ADMIN,
ADMIN, INTERNALSA_SCHEDULER,
USER, DOMAINJOHN, NORTH|USA
USER, DOMAINJOHN, SOUTH|UK // ← Nur diese 2 Kombinationen!
USER, DOMAINJANE, NORTH|GERMANY
USER, DOMAINMIKE, EAST|USA
];
Section Application;
Sales:
LOAD
*,
Upper(Region) & '|' & Upper(Country) as ACCESS_KEY
FROM [lib://Data/Sales.qvd] (qvd);
Dieses Pattern nutzt den gleichen String-Concatenation-Ansatz den du auch beim Vermeiden von Synthetic Keys und beim Design von Link Tables verwendest.
Composite Key Best Practices
| Do | Don’t |
|---|---|
Verwende eindeutige Separator: |, ~~, ### |
Verwende Leerzeichen (werden getrimmed) |
Verwende mehrere Zeichen: || oder ## |
Verwende Zeichen die in Daten vorkommen: -, _ |
| Dokumentiere das Pattern im Script | Ändere Separator später (bricht Security!) |
| Teste mit Edge Cases (nulls, special chars) | Vergesse Upper() auf alle Komponenten |
Wie funktionieren Generic Keys für komplexe Berechtigungen?
Generic Keys sind die flexibelste Section Access Methode für komplexe Berechtigungslogik mit Wildcards wie «alle Regionen» oder «alle Produkte». Das von Henric Cronström entwickelte Pattern expandiert abstrakte Berechtigungssymbole automatisch zu konkreten Datenkombinationen.
Wann Generic Keys verwenden:
- Mehr als 3 Reduction Fields
- Viele Users mit ähnlichen Patterns
- Business Users sollen Security Table pflegen (nicht IT)
- Komplexe «ANY» oder «ALL» Logic nötig
- Wartbarkeit wichtiger als einfacher Code
Das Pattern nutzt ApplyMap für die Auflösung der Berechtigungssymbole und CROSS JOIN für die Expansion:
// ===== STEP 1: Security Table mit Generic Symbols =====
Section Access;
AUTH_TABLE:
LOAD * INLINE [
ACCESS, USERID, PRODUCT_AUTH, REGION_AUTH
ADMIN, ADMIN, *, *
ADMIN, INTERNALSA_SCHEDULER, ,
USER, DOMAINUSERA, <PROD_LAPTOP>, <REG_NORTH>
USER, DOMAINUSERB, <PROD_ALL>, <REG_SOUTH>
USER, DOMAINUSERC, <PROD_DESKTOP>, <REG_ALL>
USER, DOMAINUSERD, <PROD_ALL>, <REG_ALL>
];
// ===== STEP 2: Authorization Mapping Table =====
AUTH_MAPPING:
LOAD * INLINE [
AUTH_SYMBOL, AUTH_FIELD, AUTH_VALUE
<PROD_LAPTOP>, PRODUCT, LAPTOP
<PROD_DESKTOP>, PRODUCT, DESKTOP
<PROD_TABLET>, PRODUCT, TABLET
<PROD_ALL>, PRODUCT, *
<REG_NORTH>, REGION, NORTH
<REG_SOUTH>, REGION, SOUTH
<REG_ALL>, REGION, *
];
// ===== STEP 3: Expand Generic Keys =====
PRD_MAP:
MAPPING LOAD AUTH_SYMBOL, AUTH_VALUE
FROM AUTH_MAPPING WHERE AUTH_FIELD = 'PRODUCT';
REG_MAP:
MAPPING LOAD AUTH_SYMBOL, AUTH_VALUE
FROM AUTH_MAPPING WHERE AUTH_FIELD = 'REGION';
TEMP_PRODUCTS:
LOAD DISTINCT Upper(Product) as PRODUCT
FROM [lib://Data/Sales.qvd] (qvd);
TEMP_REGIONS:
LOAD DISTINCT Upper(Region) as REGION
FROM [lib://Data/Sales.qvd] (qvd);
// Expand für Users mit "ALL" Products
SECURITY_EXPANDED:
LOAD
ACCESS, USERID,
If(PRODUCT_AUTH = '<PROD_ALL>', PRODUCT,
ApplyMap('PRD_MAP', PRODUCT_AUTH, PRODUCT_AUTH)) as PRODUCT_KEY,
If(REGION_AUTH = '<REG_ALL>', REGION,
ApplyMap('REG_MAP', REGION_AUTH, REGION_AUTH)) as REGION_KEY
RESIDENT AUTH_TABLE
CROSS JOIN LOAD * RESIDENT TEMP_PRODUCTS
WHERE PRODUCT_AUTH = '<PROD_ALL>';
CONCATENATE (SECURITY_EXPANDED)
LOAD
ACCESS, USERID,
ApplyMap('PRD_MAP', PRODUCT_AUTH, PRODUCT_AUTH) as PRODUCT_KEY,
If(REGION_AUTH = '<REG_ALL>', REGION,
ApplyMap('REG_MAP', REGION_AUTH, REGION_AUTH)) as REGION_KEY
RESIDENT AUTH_TABLE
CROSS JOIN LOAD * RESIDENT TEMP_REGIONS
WHERE PRODUCT_AUTH <> '<PROD_ALL>';
// Erstelle finalen Composite Key
FINAL_SECURITY:
LOAD ACCESS, USERID,
Upper(PRODUCT_KEY) & '|' & Upper(REGION_KEY) as ACCESS_KEY
RESIDENT SECURITY_EXPANDED;
DROP TABLES AUTH_TABLE, AUTH_MAPPING, TEMP_PRODUCTS, TEMP_REGIONS, SECURITY_EXPANDED;
// ===== SECTION APPLICATION =====
Section Application;
Sales:
LOAD *,
Upper(Product) & '|' & Upper(Region) as ACCESS_KEY
FROM [lib://Data/Sales.qvd] (qvd);
In komplexen Szenarien kann dieses Pattern auch als Subroutine gekapselt werden.
Wie implementiert man hierarchische Security?
Hierarchische Security ermöglicht, dass Manager automatisch die Daten ihres gesamten Teams sehen — inklusive aller Ebenen darunter. Qlik’s HierarchyBelongsTo Funktion löst die Org-Struktur rekursiv auf.
Section Access;
// STEP 1: Employee-Manager Hierarchy laden
EMP_MASTER:
LOAD
EMPLOYEE_ID, MANAGER_ID,
Upper(EMPLOYEE_NAME) as EMP_NAME,
Upper(EMAIL) as EMAIL
FROM [lib://HR/Employees.qvd] (qvd);
// STEP 2: Hierarchy mit HierarchyBelongsTo erstellen
HIERARCHY_TABLE:
HierarchyBelongsTo(EMPLOYEE_ID, MANAGER_ID, EMP_NAME,
MANAGER_ID, MANAGER_NAME, DEPTH)
LOAD EMPLOYEE_ID, MANAGER_ID, EMP_NAME
RESIDENT EMP_MASTER
WHERE not IsNull(MANAGER_ID);
// STEP 3: Section Access mit Rollup erstellen
SECTION_ACCESS_FINAL:
LOAD
'USER' as ACCESS,
'DOMAIN' & Upper(EMP_NAME) as USERID,
Upper(MANAGER_NAME) as EMP_ID_REDUCTION,
If(DEPTH = 0, '', 'SALARY') as OMIT
RESIDENT HIERARCHY_TABLE
WHERE DEPTH >= 0;
// STEP 4: HR Admin hinzufügen
CONCATENATE (SECTION_ACCESS_FINAL)
LOAD * INLINE [
ACCESS, USERID, EMP_ID_REDUCTION, OMIT
ADMIN, DOMAINHR_ADMIN, ,
ADMIN, INTERNALSA_SCHEDULER, ,
];
DROP TABLES EMP_MASTER, HIERARCHY_TABLE;
Section Application;
HR_DATA:
LOAD
Upper(EMPLOYEE_ID) as EMP_ID_REDUCTION,
EMPLOYEE_NAME,
Upper('Salary') as SALARY,
DEPARTMENT, PERFORMANCE_RATING
FROM [lib://HR/EmployeeData.qvd] (qvd);
Wie funktioniert HierarchyBelongsTo?
HierarchyBelongsTo löst Parent-Child Beziehungen rekursiv auf. DEPTH = 0 bedeutet der Employee selbst, DEPTH = 1 ist ein direkter Report, DEPTH = 2 ein Report des Reports.
| Input | Output | Bedeutung |
|---|---|---|
| EMP: CEO, MANAGER: null | CEO → CEO (Depth 0) | CEO sieht sich selbst |
| EMP: VP, MANAGER: CEO | VP → VP (Depth 0), VP → CEO (Depth 1) | VP sieht sich selbst. CEO sieht VP. |
| EMP: JOHN, MANAGER: VP | JOHN → JOHN (D0), JOHN → VP (D1), JOHN → CEO (D2) | Jeder Manager darüber sieht JOHN. |
Pro Tip: HierarchyBelongsTo ist perfekt für Org-Charts! Für die zugrundeliegende Datenmodellierung ist ein sauberes Fact-Dimension Design wichtig.
Wie schützt man einzelne Spalten mit OMIT?
Column-Level Security mit OMIT versteckt komplette Spalten vor bestimmten Usern. Das Field existiert für den betroffenen User nicht — es ist nicht nur leer, sondern schlicht nicht vorhanden.
Wie funktioniert das OMIT Group Pattern?
Das OMIT Group Pattern skaliert Column-Level Security für viele Users und viele Fields. Statt eine Row pro User und Field anzulegen, definierst du Gruppen von zu versteckenden Fields.
Schlechte Lösung — eine Row pro Field:
// INEFFIZIENT — 10+ Rows für EINEN User
Section Access;
ACCESS, USERID, OMIT
USER, JOHN, SALARY
USER, JOHN, BONUS
USER, JOHN, SSN
USER, JOHN, MEDICAL_INFO
USER, JOHN, BANK_ACCOUNT
Gute Lösung — OMIT Group Table:
Section Access;
SECURITY:
LOAD * INLINE [
ACCESS, USERID, REGION, OMITGROUP
ADMIN, ADMIN, ,
USER, DOMAINMANAGER, NORTH, SENSITIVE_HR
USER, DOMAINANALYST, NORTH,
USER, DOMAINCONTRACTOR, SOUTH, ALL_FINANCIALS
];
OMIT_FIELDS:
LOAD * INLINE [
OMITGROUP, OMIT
SENSITIVE_HR, SALARY
SENSITIVE_HR, BONUS
SENSITIVE_HR, SSN
SENSITIVE_HR, MEDICAL_INFO
ALL_FINANCIALS, COST
ALL_FINANCIALS, PROFIT
ALL_FINANCIALS, MARGIN
];
| Ohne OMIT Group | Mit OMIT Group |
|---|---|
| 100 Users × 10 Fields = 1000 Rows | 100 Users + 10 Fields = 110 Rows |
| Schwer zu pflegen | Einfach neue Fields hinzufügen |
| Fehleranfällig (Copy-Paste) | Eine Gruppe ändern → alle Users aktualisiert |
Wie nutzt man OMIT mit Wildcards?
Wildcards in OMIT verstecken mehrere Fields auf einmal. Dafür empfiehlt es sich, bei der Daten-Transformation konsequente Naming Conventions zu verwenden:
Section Access;
LOAD * INLINE [
ACCESS, USERID, OMIT
USER, DOMAINUSER1, COST* // ← Versteckt: COST, COST_TOTAL, COST_PER_UNIT
USER, DOMAINUSER2, *SALARY* // ← Versteckt: SALARY, BASE_SALARY, GROSS_SALARY
USER, DOMAINUSER3, INTERNAL_* // ← Versteckt: INTERNAL_NOTES, INTERNAL_ID
];
Best Practice — Naming Conventions: Verwende Prefixes/Suffixes für sensitive Fields um Wildcards zu nutzen! Beispiel: Alle Cost Fields mit
COST_prefixen, dannOMIT: COST_*.
Wie löst man den «Incomplete Visualization» Error?
Wenn ein Chart ein OMITted Field verwendet, zeigt Qlik den Error «Incomplete visualization». Hier sind 3 bewährte Lösungen:
Lösung 1: Conditional Show auf Chart-Ebene
// Chart Properties → Add-ons → Show condition:
FieldIndex('SALARY', 1) > 0
// Chart wird nur angezeigt wenn SALARY Field existiert
Lösung 2: Alternative Charts in Container
// Chart 1: Mit SALARY (Show Condition: FieldIndex('SALARY', 1) > 0)
=Sum(SALARY)
// Chart 2: Ohne SALARY — Fallback (Show Condition: FieldIndex('SALARY', 1) = 0)
='Salary information not available for your user'
Lösung 3: Field Existence Check in Expression
=If(FieldIndex('SALARY', 1) > 0,
Sum(SALARY),
Null())
OMIT Best Practices & häufige Fehler
| Don’t | Warum nicht | Alternative |
|---|---|---|
| OMIT auf Key Fields | Data Model Chaos, Synthetic Keys | Dummy Field oder Value maskieren |
| OMIT in Charts ohne Handling | Incomplete Visualization Error | Conditional Show oder Field Check |
| OMIT in Master Dimensions | Master Item wird unbrauchbar | Alternative Master Items erstellen |
| OMIT ohne Dokumentation | User versteht nicht warum Charts fehlen | Dokumentiere + Fallback Message |
Welche erweiterten Section Access Konzepte gibt es?
Was ist der Unterschied zwischen Initial Selection und Initial Data Reduction?
In Qlik Sense gibt es nur Initial Data Reduction — Strict Exclusion ist immer aktiv. QlikView hatte jedoch zwei Modi, die man im Document Properties → Opening Tab konfigurieren konnte.
| Eigenschaft | Initial Selection (QlikView) | Initial Data Reduction (empfohlen) |
|---|---|---|
| Daten | Alle Daten im RAM | Permanent reduziert |
| User kann | Selections ändern/löschen | NICHT ändern |
| Security | KEINE echte Security! | Echte Data Security |
| Verwendung | Testing, Sheet Hiding | PRODUCTION |
Best Practice QlikView: IMMER «Initial Data Reduction Based on Section Access» + «Strict Exclusion» in Production! «Initial Selection» ist nur für Testing.
Wie funktioniert Strict Exclusion im Detail?
Strict Exclusion bestimmt was passiert, wenn ein User einen Reduction Value hat der NICHT in den Daten existiert. In Qlik Sense ist es immer aktiv. In QlikView musste man es aktivieren.
| Setting | User sieht | Security Level |
|---|---|---|
| Strict Exclusion OFF | ALLE Daten | SICHERHEITSRISIKO! |
| Strict Exclusion ON | «Access Denied» Error | Sicher |
KRITISCH: Strict Exclusion OFF = Security Vulnerability! NIEMALS in Production verwenden!
Stelle sicher, dass alle Reduction Values tatsächlich in den Daten existieren. Hier hilft ein Data Quality Check im Load Script.
Was ist der Unterschied zwischen BLANK, Wildcard * und spezifischem Wert?
Es gibt 3 Optionen für die Reduction Values in Section Access:
| Option | Bedeutung | Nur für | Use Case |
|---|---|---|---|
| BLANK (leer) | Alle Werte im Data Model (wirklich alle!) | ADMIN | Reload Account, Development |
| * | Alle gelisteten Werte in Section Access | ADMIN oder USER | Manager sieht alle assigned Regions |
| NORTH | Nur dieser spezifische Wert | USER | Normal User mit Einschränkung |
WICHTIG: BLANK funktioniert nur für ADMIN Access Level! USER mit BLANK bekommen «Access Denied» (Strict Exclusion).
Was sind die Unterschiede zwischen Cloud und On-Prem Section Access?
Der Hauptunterschied liegt in der User-Identifikation: On-Premise nutzt USERID mit Windows Domain Accounts, Qlik Cloud empfiehlt USER.EMAIL über den Identity Provider.
| Field | On-Prem | Qlik Cloud |
|---|---|---|
| USERID | Empfohlen (AD_DOMAINUSER) |
Möglich, aber kompliziert |
| USER.EMAIL | Nicht verfügbar | EMPFOHLEN |
| NTNAME | Für Groups | Legacy (verwende GROUP) |
| GROUP | AD Groups | IdP + Custom Groups |
| Strict Exclusion | Konfigurierbar | Immer aktiv |
| QlikCloudGroupMode | Nicht verfügbar | 0, 1 oder 2 |
Für eine detaillierte Anleitung zur Migration, siehe den Qlik Cloud Migration Strategy Guide und den GDPR Compliance Guide für Datenschutz-Anforderungen.
Wie kopiere und füge ich Muster in der Section Access Cheat Sheet ein?
Hier sind die häufigsten Section Access Patterns zum direkten Kopieren. Jedes Pattern ist production-ready — vergiss nur nicht, die USERIDs und Field Names an deine Umgebung anzupassen.
Was ist Basic Row Reduction?
Section Access;
LOAD * INLINE [
ACCESS, USERID, REGION
ADMIN, ADMIN,
ADMIN, INTERNALSA_SCHEDULER,
USER, DOMAINJOHN, NORTH
];
Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;
Wie funktionieren Multiple Fields mit Composite Key in Section Access?
Section Access;
LOAD * INLINE [
ACCESS, USERID, ACCESS_KEY
ADMIN, ADMIN,
USER, DOMAINJOHN, NORTH|USA
];
Section Application;
LOAD *, Upper(Region) & '|' & Upper(Country) as ACCESS_KEY
FROM Data.qvd;
Wie kann ich OMIT Fields in Section Access verwenden?
Section Access;
LOAD * INLINE [
ACCESS, USERID, OMIT
USER, DOMAINJOHN, SALARY
];
Section Application;
LOAD Upper('Salary') as SALARY, * FROM Data.qvd;
Wie funktioniert Qlik Cloud mit USER.EMAIL im Section Access?
Section Access;
LOAD * INLINE [
ACCESS, USER.EMAIL, REGION
ADMIN, ADMIN@COMPANY.COM,
USER, JOHN@COMPANY.COM, NORTH
];
Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;
Was sind Gruppen in Qlik Cloud?
SET QlikCloudGroupMode = 0;
Section Access;
LOAD * INLINE [
ACCESS, USER.EMAIL, GROUP, REGION
USER, *, SALES_TEAM, NORTH
];
Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;
Am besten integrierst du Section Access in deine Three-Stage Architecture — die UPPERCASE-Konvertierung gehört in den Transform Layer.
Was sind die Zusammenfassungen und nächsten Schritte für Section Access?
Was sind die 5 goldenen Regeln für Section Access?
- IMMER einen ADMIN Account mit BLANK Reduction anlegen
- IMMER den Reload Account (SA_SCHEDULER/Owner) hinzufügen
- ALLE Fields und Values UPPERCASE machen
- Strict Exclusion enablen (QlikView) — Qlik Sense ist immer ON
- TESTEN, TESTEN, TESTEN bevor Production!
Was sind die nächsten Schritte im Section Access Guide?
1. Hands-on Practice:
- Erstelle eine Test-App mit verschiedenen Szenarien
- Implementiere alle Patterns aus diesem Guide
- Teste mit der
OSUser()Funktion - Breche absichtlich die Security um zu lernen was passiert
2. Weiterführende Lektüre:
- Henric Cronström: Complex Authorization (Generic Keys)
- Henric Cronström: Data Reduction using Multiple Fields
- Qlik Help: Section Access Reference
- Qlik Community: Best Practice Guidance
3. Verwandte Kurs-Artikel:
- Three-Stage Architecture — Security Fields im Transform Layer
- Performance Tuning — Section Access Performance optimieren
- Data Governance — Security als Teil des Governance-Frameworks
- Deployment — Section Access Apps sicher deployen
- Data Modeling — Star Schema mit Section Access