Hey everyone,
One of my frustrations with the new API is that it did not include RLS capabilities that were present in the old 1.x version. I noticed that the API has been updated to 2.0.2 and is now working with RLS within powerBI models (only against reports currently).
Power BI Article Explaining RLS and Embedded in the New API
Before making the code change you first must create a role in your PowerBI report. More than likely if you already have an embedded solution and found that RLS wasn't possible, you instead created a filter within the JavaScript and applied that to the report instead. Whatever table you applied the filter in that scenario will probably be the table used in your role(s). For me it was my Seller Table. My report had a seller table (with CompanyId) that was related to a transaction table. The goal is to only display transaction data applicable to the specific company viewing the report.
To do this I create a new role which I call "CompanyId" that will filter the seller table and in turn, the transaction table. To create a new role:
- Click on the Modeling tab
- Select Manage Roles
- Create a New Role (This will be the name of the role you pass in to the API)
- Select the dimension table that contains the members that will filter your fact data
- create the dax expression [YourColumnNametoFilter] = USERNAME(). In my case, CompanyId
That's it for the report. Unfortunately for me, it's impossible to test this because my username (or anyones username) doesn't equate to a companyID, It's something that is resolved in our web app and can be used at that point and passed into the API. I suppose if you wanted to test you could hard code a value that exists in your dim table instead of USERNAME(). Once I made this change I deployed the report
Now that the report is ready I had to make 1 small change in the code to enable RLS functionality. First, make sure you have updated your API library to 2.0.2. The change happens where you create the parameter list to generate an embed token.
The previous code:
// Generate Embed Token. var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
The new Code:
If you remember, i created a role in my report called CompanyId and this is the literal value that I pass as the role name "CompanyId". I also pass a value of the companyId and as an example here "412125". I also pass in the datasetId that I want to filter.
// Generate Embed Token. var generateTokenRequestParameters = new GenerateTokenRequest( accessLevel: "view", allowSaveAs: null, identities: new List<EffectiveIdentity> { new EffectiveIdentity(username: "412125", roles: new List<string> { "CompanyId" }, datasets: new List<string> { "DataSetId" }) });
And the results.
When running the code without RLS I get a table of the following values. You can see company 412125 along with all other companies (Not Good!).
After creating the role and and passing in the companyId as the user in the code:
Hope this helps!