2

This is related to Row-level security in Power BI. Here is a dummy table on which I want to implement this RLS.

Please check this table link

The RLS formula I am using right now is -

[location] = LOOKUPVALUE([location],[login],USERPRINCIPALNAME()) 

My end requirement is to make this RLS work on the case where if a user logs in he should see the data if the location he is in and also should see other users who are in the same location.

But lookup is throwing an error:

A table of multiple values was supplied where a single value was expected

Also, a single user can have access to multiple location and a single location could have multiple users.

How I can achieve this level of Row-level security using either Lookup or using any other possible way?

halfer
  • 19,824
  • 17
  • 99
  • 186
  • Please read [Under what circumstances may I add “urgent” or other similar phrases to my question, in order to obtain faster answers?](//meta.stackoverflow.com/q/326569) - the summary is that this is not an ideal way to address volunteers, and is probably counterproductive to obtaining answers. Please refrain from adding this to your questions. – halfer Sep 27 '18 at 22:15

2 Answers2

1

Your requirement can also be done through this way, you need to work on both the Power BI desktop and app server to get this right.

In Desktop

  1. Power BI Desktop allows you to create Roles.Click on Manage Roles and then click on Create New Role.
  2. You would need to create Roles based on the Location here.
  3. For Example Create a rule Called as Location A and click on the table and give the formula to filters on that table. For example, [Location] = "A".

So, you can create 'n' number of roles like this and then publish the dashboard.

App.PowerBI.Com

  1. Now, Open app.powerbi.com and then go to the corresponding dataset and right click on it, select security - you will find the groups there.

  2. On the Groups, enter the emailid's that should have access to it. You can add a person in multiple groups, that will allow them to see more than one group.

Testing

  1. Desktop allows you to test it as well - you can click on view as roles, to see what the user in that group sees.

Also to remember, only people who have access to the dashboard will be able to see the data inside it. So, you will need to share it with them and as well as need to add them inside the groups. If you fail to do one of it, then they won't see anything on the dashboard.

Most efficient Method

This is a better method and I think this is the one you are asking for,

[login] = username() 

The function username() automatically gets the email address of the user that is logged in.

Create the above mentioned filter on the new role in the required table. This way, you would still be adding those 50000 users manually inside the roles under the security section of the corresponding dataset.

But If they all belong to a particular group in an organization, and your Office-365 team has configured your back-end in the right way, then you will only need to enter the group.

But most companies don't have this configuration on their back-end as it is very difficult to control the data security.

Change the Data Model

To do your requirement, you also need to change your data model.

You will need to have two tables initially.

The Value Table - You can have many columns like name and all in there, but it doesn't matter.

Actual_Table

The Email Address Table For Location as your second table.

Access_Table

Now Merge the Locations from Value Table to Email Address Table and that will be your final Table. Use this for visualizations but please be very clear on DAX - as you may have duplicate rows and different values.

Final_Table

Now Create RLS on this Table. It should work.

As the name goes, Row Level Security is applied on each rows. So, the formula will be evaluated for each row individually. So, your only option is to have a flat table with all the values.

  • Well, thanks for that. But this is just a dummy data. In the original data I have 50,000 users. So, it is not really possible to assign roles to these many users. That's why I was looking for a better approach. – Deepesh Vashistha Sep 27 '18 at 17:32
  • There is a way, give me a day and I will answer with an working prototype. – Student of the Digital World Sep 27 '18 at 19:04
  • thanks a lot Sid29, I am waiting eagerly for your working Prototype. – Deepesh Vashistha Sep 28 '18 at 04:21
  • Thank you @Sid29, as you can see in my question, in the DAX formula I have used USERPRINCIPALNAME() which helps me in doing the same stuff what you are telling right now. But my end requirement is that if a user logs-in he should also see the details of other users from same location. With normally using USERNAME(), I am only seeing details of that person, but as I've shown in my question a user could have different locations too. So, in that case, do you have any idea how to make it work? Thank you! – Deepesh Vashistha Sep 28 '18 at 13:04
  • @DeepeshVashistha oops, tricky one isn't it. You need to have a flat table then. Updated. This might be helpful to you. – Student of the Digital World Sep 28 '18 at 14:08
  • Thanks for this Sid. One thing, say if we take this table as our flat table [link](https://i.stack.imgur.com/LOt0V.png) So, as you can see there is duplicate values in it.In RLS, here is the formula I am using [location] = LOOKUPVALUE([location],[login],USERPRINCIPALNAME()). This is checking which user logs in and if there is any other user from same location. Then it will return all the user from same location. But if a user is having access to multiple locations then I am getting error as I've mentioned in my question. Using this table can you help me with DAX? It's really challenging. – Deepesh Vashistha Sep 28 '18 at 17:23
  • @DeepeshVashistha Are you sure you have a location created between the Location of this table to others ? Examine that relationship - Creating a relationship will be a better way to filter out data. – Student of the Digital World Oct 01 '18 at 14:40
  • Did you find a solution to get this working, I am working through a similar scenario: [link](https://stackoverflow.com/questions/56221161/dax-bring-back-all-records-from-a-team-where-the-logged-in-user-is-in-the-team) – Pete May 21 '19 at 12:17
0

I answered a question very similar to this one on another page. I will copy it here because I added a bit for the lookup function. Embedded Power BI: Add Multiple Users in Row Level Security and assign different roles

If you have more than one data to filter against in a role, pass the list as a string path to RLS, parse it into a table, then return the row when it matches with a value in the column.

We do this if we are not actually passing username, but for cases like multiple sales offices, or making a view that compares data from multiple user accounts, or when a user belongs to different hierarchies in an organization, or basically any time you want to use multiple filters..

example input using sales ids

//Username() = "020104010|020104061|020104303|020104304"

//DAX
var userIds = Username()
VAR tbl=
    GENERATE (
        GENERATESERIES(1,PATHLENGTH(UserIds),1),
        ROW ( "Key", PATHITEM ( userIds, [value]))
    )

VAR valueList =
    SELECTCOLUMNS ( tbl, "Key", [Key] )

return  [sales_id_column] in valueList

If you need to add lookup functions, you can apply it when the ROW() statement is called.. it will look like this:

VAR tbl=
GENERATE (
    GENERATESERIES(1,PATHLENGTH(UserIds),1),
    VAR CurrentKey = [Value]
    RETURN
    ROW ( "Key", LOOKUPVALUE(Table[c1],Table[c2], PATHITEM ( userIds, CurrentKey )))
)

There is also a case when the table has a many to many relationship and cannot use multiple roles as identity. Or for this case specifically when you only want to use one role to filter many tables. In that case the username looks like this:

Username() = "Username:Bob|Location:A|Location:C"

The code will have an extra step to parse the inner path after you change the ":" to a "|". Then use a if conditional to check if the current table filters for this role. This approach supports a claims-based authorization where only one role needs to be created in RLS and everything can be done client-application side.

runtime is O(k(n log m)) where m is the number of claims you have applying RLS in the current table, n is the number of rows in the table, and k is the number of tables you are applying RLS on

Jeff
  • 810
  • 8
  • 18