4
votes

We have developed a Power BI report and we have a requirement to embed the Power BI report inside an Angular Application. The Angular Application works with OAuth authentication. We have seen how to embed the Power BI Report (as mentioned in the link - Embedding for Customers - https://docs.microsoft.com/en-us/power-bi/developer/embedding#embedding-for-your-customers)

We also have a requirement to do a fine grained authorization within the Power BI report. Is it possible to filter the data based on the user logged in to the Angular UI Application?

2

2 Answers

2
votes

Yes, it's possible, I've used Ngx-power-bi. Try this:

private powerBiService: NgxPowerBiService;
private pbiContainerElement: HTMLElement;

private reportId = "YOUR REPORT ID";
private groupId = "YOUR GROUP ID";
private filterPaneEnabled= false;
private navContentPaneEnabled= true;
    
constructor(private authService: AuthService,private dashboardService:DashboardService) {
this.powerBiService = new NgxPowerBiService();
}

ngOnInit() {

//Get the token from backend, You may use switchMap or flatMap 
//to get the user data (table, column, value etc)

this.dashboardService.getAccessToken().pipe(untilDestroyed(this)).subscribe(token=>{
    const config = {
        type: 'report',
        id: this.reportId,
        embedUrl:
          'https://app.powerbi.com/reportEmbed?' +
          'reportId='+this.reportId +
          '&groupId='+ this.groupId,
        accessToken:token.accessToken,
        settings: {
          filterPaneEnabled: this.filterPaneEnabled,
          navContentPaneEnabled: this.navContentPaneEnabled
        },
        filters:[{
            $schema: "http://powerbi.com/product/schema",
            filterType:1,
            target: {
              table: "Master", // filter table
              column: "companyId" // filter column
            },
            operator: "In",
            values: [101]   // value that you need to filter

          }]
      };
    this.pbiContainerElement = <HTMLElement>(document.getElementById('pbi-container'));
    this.powerBiService.embed(this.pbiContainerElement, config);
})

   
   
1
votes

You can achieve this in two ways - define filters when embedding the report or with Row-Level Security.

When embedding Power BI elements, you are initializing a configuration. One of the properties of this object are the filters to be pre-applied on the report, when loaded. Currently these are the supported filter types:

export enum FilterType {
  Advanced = 0,
  Basic = 1,
  Unknown = 2,
  IncludeExclude = 3,
  RelativeDate = 4,
  TopN = 5,
  Tuple = 6
}

These types corresponds to the filters, that you can apply in the report when shown in a browser or in Power BI Desktop. For more information what properties each filter type has and how to use it, see Filters page in the documentation, but for example a basic filter needs to define the table and column, on which the filter will be applied, comparison operator, and of course values, e.g.:

const basicFilter: pbi.models.IBasicFilter = {
  $schema: "http://powerbi.com/product/schema#basic",
  target: {
    table: "Store",
    column: "Count"
  },
  operator: "In",
  values: [1,2,3,4],
  filterType: 1 // pbi.models.FilterType.BasicFilter
}

or

const basicFilter = {
  $schema: "http://powerbi.com/product/schema#basic",
  target: {
    table: "Store",
    column: "Count"
  },
  operator: "In",
  values: [1,2,3,4],
  filterType: 1 // pbi.models.FilterType.BasicFilter
}

Then set this filter in the configuration prior embedding:

var config = {
    type: embedType,
    accessToken: accessToken,
    tokenType: tokenType,
    embedUrl: embedUrl,
    id: embedId,
    dashboardId: dashboardId,
    permissions: permissions,
    settings: {
        filterPaneEnabled: false,
        navContentPaneEnabled: true
    },
    filters: [basicFilter]
};

Note, that in this case you should hide the filter pane, by setting filterPaneEnabled: false, otherwise the user will see the pre-applied filter in the filters pane and will be able to change it or remove it! But if you hide the filters pane, this will limit the users options to analyze the data by only using the slisers and other options provided in the report itself. So using RLS may be a better idea, but it requires a dedicated capacity for your workspace (i.e. buying Power BI Premium or Power BI Embedded).

To use RLS you must define one or more roles in your report. For each role a DAX expression will be defined to filter the data. Then for each of your users, you can decide which role or roles to give and the report will show only the data accessible to these roles. Then use the AAD token that you get, to call GenerateTokenInGroup REST API and pass the roles that you want your user to have in the request body:

{
  "accessLevel": "View",
  "identities": [
    {
      "username": "[email protected]",
      "roles": [
        "sales",
        "marketing"
      ],
      "datasets": [
        "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
      ]
    }
  ]
}

Then use the above acquired token to embed the report and don't forget to change the value of tokenType property in the configuration to be 1 (embed) instead of 0 (AAD), if needed.

This way you can leave the filters pane visible, because the security policies will be applied under the hood by the engine.