Sviluppare e testare le regole RLS in Power BI
Develop and test RLS rules in Power BI.
Molto spesso, non tutti gli utenti dovrebbero avere il permesso di accedere a tutti i dati in un report. Qui spiegherò come sviluppare regole di RLS in Power BI per configurare l’accesso e come testarle.
Introduzione
Molti dei miei clienti vogliono limitare l’accesso ai dati nei loro report in base a specifiche regole.
L’accesso ai dati è chiamato Row Level Security (abbreviato in RLS).
Puoi trovare molti articoli su RLS in Power BI su Nisoo.
Ho aggiunto due di essi nella sezione Riferimenti qui sotto.
- Le 3 competenze tecniche essenziali che ogni leader dei dati ha bisogno per avere successo
- 6 casi d’uso in Python in cui * e ** sono utili
- Cosa sono i database vettoriali e perché sono importanti per gli LLM?
Anche se tutti gli articoli fanno un buon lavoro nel spiegare le basi, mi manca sempre una spiegazione su come sviluppare regole più complesse e come testarle facilmente.
In questo articolo, spiegherò le basi di RLS e aggiungerò complessità passo dopo passo.
Inoltre, ti mostrerò come utilizzare DAX Studio per costruire query per testare le regole RLS prima di aggiungerle al modello dati.
Quindi, eccoci qui.
Scenario
Utilizzo lo scenario in cui gli utenti ottengono l’accesso ai dati delle vendite al dettaglio in base ai negozi o alle posizioni geografiche dei negozi all’interno dell’azienda, compresa una combinazione di entrambi.
Nel modello dati Contoso, utilizzo le seguenti tabelle:

Creo il seguente report per testare i miei risultati:

Crea una regola semplice
Per creare una regola di RLS, è necessario aprire l’editor del ruolo di sicurezza:

Successivamente, è possibile creare un nuovo ruolo e impostare il nome per questo ruolo:

Nel mio caso, ho messo il nome “StorePermissions”.
Ora posso iniziare ad aggiungere un’espressione per controllare l’accesso alla tabella Store:

Abbiamo un nuovo editor più semplice per le regole RLS da alcuni mesi.
Nel mio caso, voglio aggiungere un’espressione DAX. Quindi, faccio clic sul pulsante “Passa all’editor DAX”.
All’inizio, aggiungo l’espressione più semplice possibile: TRUE ()

Per capire le regole RLS, devi sapere che l’accesso è controllato dall’output dell’espressione nell’editor della regola RLS.
L’utente otterrà l’accesso se l’output dell’espressione non è vuoto o FALSE().
In principio, qualsiasi espressione nell’editor della regola RLS viene aggiunta come filtro a qualsiasi query. Vediamo l’effetto di questa prima espressione prima di spiegare questo in modo più dettagliato.
Per testare la regola, salvo l’espressione e chiudo l’editor.
Ora posso visualizzare il report con la nuova regola:

In cima alla pagina del report, vedrai un banner giallo che indica che stai guardando il report utilizzando la regola StorePermission.
Dal momento che la regola StorePermission non limita l’accesso, non vedrai alcuna differenza.
Proviamo qualcosa di diverso.
Ora cambio l’espressione nella regola RLS in FALSE().
Quando testo la regola, non vedrò alcun dato:

Ciò dimostra che i dati sono accessibili se l’espressione non restituisce FALSE().
Query di test
Per comprendere questo effetto in dettaglio, lascia che mostri una query DAX per ottenere il risultato senza alcuna restrizione:
EVALUATE SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] )ORDER BY Store[Store]
Quando aggiungo una regola RLS con TRUE(), come mostrato sopra, la query cambia in una query simile a questa:
EVALUATE FILTER( SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] ) ,TRUE() )ORDER BY Store[Store]
Ho racchiuso la query all’interno di una funzione FILTER() e ho aggiunto TRUE() come espressione di filtro.
Negli esempi seguenti, utilizzerò CALCULATETABLE(), poiché la scrittura del codice è più efficiente e flessibile.
Ne parlerò un po’ più avanti.
Rendiamolo più complesso
Successivamente, voglio limitare l’accesso a tutti i negozi contenenti la stringa “Contoso T”.
Per questo, cambio l’espressione nell’editor della regola in quanto segue:
CONTAINSSTRING('Store'[Store], "Contoso T")
Quando testo la regola, ottengo il seguente risultato:

Testare la regola con una query DAX
Sarebbe bello testare l’esito di tale regola con una query DAX.
In questo caso, utilizzo la seguente query in DAX Studio per verificare il risultato:
EVALUATE CALCULATETABLE( SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] ) CONTAINSSTRING('Store'[Store], "Contoso T") = TRUE() )ORDER BY Store[Store]
La parte interna, con SUMMARIZECOLUMNS(), genera la tabella di output.
In questo caso, sono interessato solo alla lista dei negozi.
Quindi, racchiudo la chiamata SUMMARIZECOLUMNS() con CALCULATETABLE() per aggiungere un filtro alla query.
In questo caso, aggiungo l’espressione dalla regola RLS, includendo una verifica “= TRUE()”.
Il risultato è il seguente:

Ma cosa succede sotto il cofano?
Guardiamo la query del motore di archiviazione:

E cosa succede quando applico la regola RLS a questa query?
Posso applicare una regola RLS da DAX Studio con pochi clic:

La query del motore di archiviazione è la seguente:

La prima query (Linea 2) recupera l’elenco di tutti i negozi.
La seconda query include la regola RLS nella clausola WHERE.
Invece di avere l’elenco dei negozi corrispondenti (in base al filtro), vediamo una riga criptica, che include la regola RLS.
Puoi vedere che il risultato della query del motore di archiviazione (SE) contiene ancora 309 righe, come sopra, che è il numero di tutti i negozi + 3 righe. Un suggerimento del motivo per cui abbiamo la discrepanza di 3 righe si trova nel testo sotto la query SE: Dimensioni stimata: righe = 309
Il numero effettivo di righe restituite potrebbe essere effettivamente 306.
Ma questa analisi mostra che le regole RLS sono applicate dopo il motore di archiviazione, poiché il risultato della query contiene solo 21 righe: tutti i negozi che iniziano con “Contoso T”.
Questo è importante, poiché il motore di formule (FE), che calcolerà il risultato finale dopo il motore di archiviazione, è single-threaded e può utilizzare solo un core della CPU.
Mentre il SE è multi-threaded e può utilizzare più core della CPU.
Di conseguenza, dobbiamo astenerci dal scrivere codice inefficiente nella regola RLS.
Regole combinate
Successivamente, voglio combinare due espressioni:
- Solo negozi che iniziano con “Contoso T”
- Solo negozi in Europa
Per ottenere questo, aggiungo una seconda espressione alla tabella Geografia usando l’editor semplice:

Quando passo all’editor DAX, ottengo la seguente espressione:

Si noti l’uso dell’operatore di uguaglianza stretto.
Cambiare l’operatore di uguaglianza semplice per la tua espressione può essere necessario.
Questo è il risultato durante il test della regola:

La query DAX per questa regola sarà così:

Ora, aggiungiamo un altro livello di complessità alla regola RLS:
Voglio limitare l’accesso ai negozi che:
- Il nome dei negozi inizia con “Contoso T” e si trovano in Europa o
- Il nome dei negozi inizia con “Contoso S” e si trovano in Nord America
Questa volta, inizio con la query DAX. Questo è il modo più semplice per sviluppare e testare l’espressione.
Prendo la prima query e la racchiudo con l’espressione di filtro.
Poiché devo filtrare due tabelle (Store e Geography), devo usare FILTER() e RELATED() :
EVALUATE CALCULATETABLE( ADDCOLUMNS( SUMMARIZECOLUMNS(Store[Store], 'Geography'[Continent]) ,"Retail_Sales", 'All Measures'[Retail Sales] ) ,FILTER(Store ,OR(CONTAINSSTRING('Store'[Store], "Contoso T") && RELATED(Geography[Continent]) = "Europe" ,CONTAINSSTRING('Store'[Store], "Contoso S") && RELATED(Geography[Continent]) = "North America") ) )ORDER BY [Retail Sales] DESC, 'Geography'[Continent], Store[Store]
Ho bisogno della funzione RELATED() poiché uso FILTER() per iterare attraverso la tabella Store e ho bisogno della colonna Continent dalla tabella Geography.
Poiché la tabella Geography è dalla parte uno della relazione, posso usare RELATED() per ottenere la colonna Continent.
Questo è il risultato:

Successivamente, dobbiamo tradurre questo filtro in una regola RLS.
Per la regola RLS, possiamo rimuovere la funzione FILTER(), poiché la regola RLS funziona intrinsecamente come un filtro.

Si noti che ho rimosso l’espressione dalla tabella “Geography”.
Quando testo questa regola in Power BI, ottengo il seguente risultato, che corrisponde al risultato della query DAX:

Per testare la regola RLS, ad esempio, quando si desidera ottenere solo l’elenco di negozi filtrati, è possibile scrivere una semplice query con solo la funzione FILTER():

Configurare l’accesso in base al login dell’utente
Fino ad ora, abbiamo esaminato le regole RLS statiche.
Ma la maggior parte delle volte abbiamo bisogno di regole basate sul login dell’utente.
Per ottenere questo, abbiamo bisogno di una tabella che mappi l’utente alle righe a cui l’utente ha accesso.
Ad esempio, una tabella come questa:

Dopo aver aggiunto la tabella al modello dati, dobbiamo aggiungere una relazione tra la nuova tabella e la tabella “Geografia”:

La relazione tra la nuova tabella “Accesso alla geografia” e la tabella “Geografia” deve essere configurata correttamente.
Dopo aver aggiunto la relazione, Power BI la configura come una relazione 1:n, con la tabella “Geografia” sul lato uno e il filtro che fluisce dalla tabella “Geografia” a “Accesso alla geografia”.
Ma vogliamo filtrare la tabella “Geografia” in base a una regola RLS (un filtro) su “Accesso alla geografia”. Per questo motivo, dobbiamo cambiare la direzione di cross-filter in entrambi:

Inoltre, dobbiamo impostare il flag su “Applica filtro di sicurezza in entrambe le direzioni”, poiché Power BI ignora l’impostazione di direzione di cross-filter quando si applicano le regole RLS.
Ora possiamo aggiungere la regola RLS:

Ricorda di rimuovere qualsiasi espressione di filtro sulla tabella Store prima di aggiungere questa regola.
Quando testo la regola RLS, ottengo questo:

Per scoprire cosa succede, torniamo all’editor della regola RLS e cambiamo la vista per la regola in DAX:

L’editor semplice della regola RLS non riconosce le funzioni DAX e le aggiunge come testo per il filtro.
Dobbiamo cambiare l’espressione in questo modo:

Ora il risultato è come previsto:

La Card nell’angolo in alto a sinistra della pagina del report contiene una Misura con la funzione USERPRINCIPALNAME() per garantire che l’utente corretto sia attivo durante il test.
Posso persino testare una regola RLS utilizzando un altro utente:

È divertente che questo utente non debba esistere. Deve solo essere contenuto nella lista “Accesso geografico”.
Ecco il risultato del test:

Nella riga gialla in alto, è possibile vedere l’utente attivo durante il test.
Conclusione
Ho mostrato come creare regole RLS elementari e come testarle.
Poi ho aggiunto maggiore complessità e ho analizzato gli effetti delle regole RLS sul motore di archiviazione sottostante.
Abbiamo visto che il motore di formule elabora parte della regola RLS. Pertanto, dobbiamo scrivere codice efficiente nelle regole RLS.
Sapere come testare le regole RLS prima di implementarle nel modello dei dati è molto importante.
È molto più facile capire i risultati errati capendo come la regola viene applicata al modello dati.
Infine, ho aggiunto regole RLS dinamiche basate sull’utente al modello.
Queste regole sono più difficili da testare in una query DAX, poiché è necessario conoscere i dati a cui ogni utente può accedere per scrivere la query di test corretta per convalidare il risultato.
Spero di averti dato alcuni suggerimenti per semplificarti la vita con la funzione RLS in Power BI.
Riferimenti
Puoi trovare un elenco delle funzioni di sicurezza in Power BI in questo articolo:
4 + 2 funzioni di sicurezza in Power BI
Un anno dopo il mio primo articolo su questo argomento, ecco un aggiornamento sulle nuove funzioni di sicurezza in Power BI
towardsdatascience.com
Puoi trovare una spiegazione semplice su Row Level Security in Power BI sulla pagina della Community di Power BI (ora Fabric): Row-level security (RLS) with Power BI — Power BI | Microsoft Learn.
Posso consigliare questo articolo di Nikola Ilic, dove puoi ottenere un punto di partenza su RLS:
La guida definitiva alla sicurezza a livello di riga e oggetto in Power BI
“Chi vede cosa nel rapporto?” è una delle domande chiave sulla sicurezza in Power BI. Impara due possibili modi per implementare…
towardsdatascience.com
Un altro buon articolo introduttivo su Row-Level-Security in Power BI di Elias Nordlinder:
Come implementare Row Level Security in Power BI (Parte I)
La Row-Level Security è un modo per filtrare i dati in modo diverso a seconda dei diversi ruoli. Questo potrebbe essere fatto staticamente…
elias-nordlinder.medium.com
Visita la mia lista di storie per maggiori informazioni sulla funzione FILTER() e su come analizzare la query DAX con DAX Studio.
Utilizzo il set di dati di esempio Contoso, come nei miei articoli precedenti. Puoi scaricare gratuitamente il dataset ContosoRetailDW da Microsoft qui.
I dati di Contoso possono essere utilizzati liberamente sotto la licenza MIT, come descritto qui.
Unisciti a Nisoo con il mio link di referral – Salvatore Cagliari
Come membro di Nisoo, una parte della tua quota di iscrizione va agli scrittori che leggi e ottieni l’accesso completo a ogni storia…
Nisoo.com