Ravindra BagaleCourses & study guides Track your progress

Guides

Row-Level Security in Power BI

Row-level security (RLS) is a filter on rows, by role, so one report serves many people. The Pune role sees Pune’s 40. The Mumbai role sees Mumbai’s 150. You test with View as before anyone else opens the report. This page is how to set that up. It is not a way around security.

Friends! Two city managers should not see each other’s sales. Why one report? Because two PBIX files drift apart. How? We put a filter on the Store table for each role, the filter walks into Sales, and we view as Pune before we assign a person in the Service. The right person, the right rows.

Quick answer

Vertical path:

  1. Modeling → Manage roles.
  2. New role named Pune. On Store, City equals Pune.
  3. New role named Mumbai. On Store, City equals Mumbai.
  4. Modeling → View as → Pune. The card must read 40, not 190.
  5. Stop viewing. View as Mumbai. The card must read 150.
  6. After publish, semantic model → Security → add members to each role. Consumers must be Viewers, not workspace builders.
Role filter on Store[City]  →  Sales rows that match  →  the card

The rows each role keeps

Sales:

Order Store ID Amount
A S1 100
B S1 50
C S2 40

Store:

Store ID City
S1 Mumbai
S2 Pune
  1. No role, you as the author in Desktop: 190.
  2. Role Pune: Store keeps S2. Sales keeps order C. Card 40.
  3. Role Mumbai: Store keeps S1. Sales keeps A and B. Card 150.
  4. The hidden rows are not on the visual, and they are not in the export for that role.
  5. A measure cannot be used as a back door to those rows. The role filter stays. Do not go looking for a trick. Set the role correctly instead.

Put the filter on the dimension (Store), not only on a visual. A hidden page is not security. Anyone who can build can see the fields.

What do I need before this guide?

Before and after (look at the tables first)

Before row-level security No role, total 190 for everyone.

Before - Everyone sees all rows. Too many rows

After row-level security Pune role 40 and Mumbai role 150.

After - Role filter. Test with View as

How to create and test the roles

Role filters rows Role filters rows. Pune role: Store City = Pune → 40 Mumbai role: Store City = Mumbai → 150 Filter sits on the dimension. It walks into Sales. Role filters rows Pune role: Store City = Pune → 40 Mumbai role: Store City = Mumbai → 150 Filter sits on the dimension. It walks into Sales.

A role filters Store[City]. Pune keeps 40. Mumbai keeps 150. The filter walks into Sales.

  1. Modeling → Manage roles → New → name it Pune.
  2. Select the Store table. Add a filter: City is Pune. Or switch to the DAX editor and use [City] = "Pune".
  3. Save. Create Mumbai the same way with "Mumbai".
  4. Modeling → View as → tick Pune → OK. A bar says you are viewing as that role.
  5. Read the card. It must be 40. Open the table. Only Pune rows.
  6. Stop viewing. Repeat for Mumbai and 150.
  7. If a role sees 190, the filter is on the wrong table, the relationship is missing, or you are not really viewing as that role.
Test, then assign Test, then assign. View as Pune before you share. Card must say 40. Service: semantic model → Security. Add Viewers, not Members. Test, then assign View as Pune before you share. Card must say 40. Service: semantic model → Security. Add Viewers, not Members.

View as proves the role before you assign people. In the Service, add members under the semantic model Security page.

In the Service, after you publish:

  1. Workspace → semantic model → Security.
  2. Select the Pune role. Add the Pune readers, or a security group.
  3. Add Mumbai readers to the Mumbai role only.
  4. Use Test as role. Check the card, not only the city name.
  5. Share through Viewer or an app. Do not add those readers as Admin, Member, or Contributor.

Builders see all rows. If you test with your own Admin account, you will see 190 and think the role failed. Test as the role, or with a Viewer account.

One role for many managers (dynamic)

Static roles are one filter value per role. When every manager has a sign-in and their email is stored on the Store row, one role can compare that column to the person who opened the report:

[Manager Email] = USERPRINCIPALNAME()
  1. USERPRINCIPALNAME returns the sign-in, usually an email-style name.
  2. Example: manager.pune@example.com on the Pune store row. That person sees 40.
  3. The spelling must match the sign-in exactly. An old address sees nothing. That is a data fix, not a reason to remove the role.
  4. View as → Other user, and type the example address, to test without borrowing anyone’s password.
  5. Hide the security table from report view if you add a mapping table. Readers do not need to browse the list of who sees what.

Object-level security is different: it hides a whole table or column from a role. This guide does not set that up. Row-level security is the row filter above.

If a person is in two roles, they see the rows of both. A person in Pune and Mumbai sees 190. Add people only to the role they should have.

Mistakes and calm fixes

Symptom Likely cause Fix
View as still shows 190 Filter on the wrong table, or no relationship Filter Store[City]; check the line
Manager sees every city They are Admin, Member, or Contributor Give Viewer or app access
Manager sees nothing Email does not match, or they were not added to the role Fix the member list or the address
Blank city and a full total Role not tested View as before you assign people

Ravindra Bagale's Tip

Interview line: “RLS filters rows by role so each person sees only their cities. I test with View as, I assign viewers in the Service, and I never treat a hidden page as security.” Got it?

Practice task

  1. Create Pune and Mumbai roles on Store[City].
  2. View as Pune. Record the card (40).
  3. View as Mumbai. Record the card (150).
  4. Stop viewing and confirm you, the author, see 190 again.
  5. Write who will be a Viewer in the Service, and who must not be a Member.

Learn it properly

Course lessons:

Related: Workspaces · Relationships

Got it? One report, a role per audience, View as before you share. Pune sees 40. Mumbai sees 150. That is the point of row-level security. Let us go ahead.

Frequently asked questions

What is row-level security?

A role filter that limits which rows a person can see in one shared report.

Where do I put the filter?

On the dimension, such as Store[City], so it walks into Sales through the relationship.

How do I test?

Modeling, View as, then tick the role. In the Service, Test as role.

Why does a Member see every city?

Row-level security applies to viewers, not to workspace builders. Give consumers Viewer or an app.

What is dynamic RLS?

One role that compares a column, such as Manager Email, to USERPRINCIPALNAME() for the person who signed in.

Is a hidden page security?

No. Hide rows with a role. A hidden visual is not a security boundary.