PowerBI Embedded API— RLS
Obter Token de Inserção passando regras de RLS usando “CUSTOMDATA()” .
Dentre várias ferramentas para análise de dados, o PowerBI tem de destacado por sua eficiência mista, disponibilidade de conectores de fontes de dados e um excelente enquadramento em todo ecossistema Intelligent Business Applications.
Com um grande diferencial, o PowerBI traz disponível algumas licenças que podem apontar diretamente para seu modelo de negócio com generosos recursos de processamento, escalonamento e APIs.
O PowerBI Embedded é uma dos 4 tipos de licença disponíveis além do Premium per User, Premium Per Capacity, Pro e Free.
Estarei falando um pouco sobre, e realizando uma breve demonstrações de de chamada de API para obtenção de Token de Inserção com RLS e usando CustomData para envio de valores.
RLS (Segurança em Nível de Linha) O RLS permite controlar o acesso a linhas em uma tabela de banco de dados por meio de associações de grupo. Ao inserir itens, você pode usar o RLS para restringir o acesso do usuário a linhas de dados específicas. Com o RLS, usuários diferentes podem trabalhar com os mesmos itens, mas ver dados diferentes.
CustomData() “Função DAX que pode ser usada no PowerBI e outras ferramentas, e que retorna o conteúdo da propriedade CustomData na string de conexão, sendo possível enviar estes dados na requisição da obtenção de Token Embed.”
Estudo de caso
Uma empresa deseja disponibilizar painéis do PowerBI para seus Colaboradores e Clientes, e tem como objetivo principal o acesso destes através do site da empresa, local onde está armazenada a base de usuários em geral, não sendo necessária uma conexão com o Azure Active Directory.
Considerando um cenário de que deve ser aplicado Nível de Segurança de Linha (RLS) para seus clientes e colaboradores, onde Clientes possuem características de Grupo, ou seja, cada cliente pode possuir mais de uma empresa do mesmo grupo. Deste modo Clientes possuem acesso aos itens (Empresas) que estão dentro do seu grupo principal de forma única, já Gerentes possuem acesso à inúmeros grupos (Clientes) e com isso inúmeras empresas.
Qualquer usuário com regra de Admin aplicada terá acesso à todos os dados.
Deste modo a estrutura de acesso por RLS se distribui por este aspecto:
Estrutura relacional das tabelas
Tabela [customers_base] armazena informações básicas de ID do Cliente (Empresa), ID do Grupo (Cliente) e uma coluna preenchida com número inteiro (1) para ser usado na regra de ADMIN.
Tabela [co2_table] armazena informações de percentual de recuperação de níveis de CO2 distribuído a nível Empresa.
Configurando Regras de RLS no PowerBI Desktop:
ADMIN:
Considerando que as permissões de usuários são gerenciadas diretamente pelo site da empresa, e que independente da identidade do usuário, ao aplicar a regra de Admin o mesmo terá total acesso. Visando também quesitos de velocidade na filtragem o filtro por DAX fica simplesmente assim:
CUSTOMER:
Considerando que o cliente possui acesso a somente um grupo e este valor de grupo será atribuído durante a chamada de API, é então aqui que posso aplicar minha função de CUSTOMDATA(), onde ela será utilizada trazer a String de informação do [GROUP_ID].
O valor esperado é parecido com “0000123”.
MANAGER:
Como parte da regra de negócio, o Gerente possui acesso à vários grupos, deste modo é necessário ser enviada mais de um ID de Grupo.
ContainsString(CUSTOMDATA(), [GROUP_ID])
Considerando esta regra e sua fragilidade de filtragem com a função CONTAINSSTRING(), deve ser notado alguns pontos importantes ao usar esta função.
Isto irá filtrar a tabela através de valores “contidos”, ou seja se for enviado um ID como “7”, poderei ter problemas com a qualidade desta filtragem.
Sendo necessário então um aperfeiçoamento da função, mas, para um cenário simples onde podemos aplicar mascara em IDs para aumentar o número de caracteres, pode-se ter um resultado estatisticamente viável.
Ou seja, posso aumentar o número de caracteres usando mascaras para reduzir a similaridade e assim não dar errado fazendo o uso desta função.
Assim: Antes “7”, Agora: “0000007”
O Gerente poderá receber dados através da função CustomData desta forma:
ContainsString(“0000007,0001234,0007347”, [GROUP_ID])
Obtenção de Token com RLS e CustomData
Antes de falarmos sobre RLS, gostaria de salientar que para inserir relatórios do PowerBI Embedded no site demanda processos de implementação/desenvolvimento tanto do back-end quanto do front-end, logo os processos de inserção após todo ambiente do Azure e PowerBI configurado, (Provisionamento de Capacidade, criação de Entidade de Serviço e concessões de acessos necessários no Azure e no PowerBI), poderemos então resumir o processo restante com a obtenção de 3 informações relevantes para renderização dos relatórios, Token de Autorização, URL de Inserção e Token de Inserção.
1- Token de Autorização, este que você obtém através de método POST, enviando as informações abaixo:
POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
Request Headers:
Content-Type: application/x-www-form-urlencoded
Keep-Alive: true
Body:
grant_type: client_credentials
client_id: "Id da Entidade de Servico"
client_secret: "Secret gerada para a Entidade de Servico"
scope: https://analysis.windows.net/powerbi/api/.default
Poderá testar também em: Get a Embed Token
2- URL de Inserção
Fazendo o uso do Token de Autorização obtido na primeira etapa, pode-se obter URL de inserção em Grupo desta forma:
GET https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports
Authorization: Bearer Token
Isto irá trazer como resposta um json com informações de todos os relatórios contidos em um Workspace, passando o ID do mesmo durante a chamada em “{groupId}”.
Resposta: 200 — OK
{
"value": [
{
"datasetId": "cfafbeb1-8037-4d0c-896e-a46fb27ff229",
"id": "5b218778-e7a5-4d73-8187-f10824047715",
"name": "SalesMarketing",
"webUrl": "https://app.powerbi.com/groups/f089354e-8366-4e18-aea3-4cb4a3a50b48/reports/5b218778-e7a5-4d73-8187-f10824047715",
"embedUrl": "https://app.powerbi.com/reportEmbed?reportId=5b218778-e7a5-4d73-8187-f10824047715&groupId=f089354e-8366-4e18-aea3-4cb4a3a50b48"
}
]
}
Poderá testar no Postman e em Get Reports in Group
(Neste ambiente de teste não será utilizado o token de autorização pois já é necessário se autenticar para utiliza-lo.)
Ok, agora temos uma URL de Inserção (Embed URL).
3 — Token de Inserção (Embed Token)
Finalmente chegando no último item, gostaria de relembrar nosso estudo de caso, onde os dados de usuários estão armazenados no site da empresa e onde o time de desenvolvimento ficará responsável por enviar no corpo de solicitações HTTP informações como identidades de usuário e ids de objetos do PowerBI como Reports e Dataset.
Já sabemos que é necessário um Token de Autorização para obter um Token de inserção (Isso mesmo, dois), logo pode-se aplicar no corpo da solicitação as regras de RLS para os usuários, e também enviar dados via CustomData, desta forma ainda considerando nosso token de autorização:
Solicitação:
POST https://api.powerbi.com/v1.0/myorg/GenerateToken
Authorization: Bearer Token
Corpo da Solicitação com RLS e CustomData:
MANAGER:
{
"datasets": [
{
"id": "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
}
],
"reports": [
{
"allowEdit": false,
"id": "5b218778-e7a5-4d73-8187-f10824047715"
}
],
"identities": [
{
"username": "gerente@email.com",
"roles": ["MANAGER"],
"CustomData": "{\"0000007\",\"0001234\",\"0007347\"}"
,
"datasets": [
"cfafbeb1-8037-4d0c-896e-a46fb27ff229"
]
}
]
}
Para fazer o envio de múltiplos valores, observe que foi utilizado contra barra \ na solicitação para envio de caracteres especiais no Json, isto funcionará perfeitamente quando o PowerBI receber estes dados e realizar a filtragem da tabela.
Para um teste você pode usar o Postman ou através de: Get-EmbedToken e usando o PBI Playground Developer.
Demais chamadas para Admin e Customer funcionarão simples desta forma:
CUSTOMER:
Para um valor exclusivo do grupo.
{
"datasets": [
{
"id": "b4abcs-5xxx-4533-8fbhgg-123445b"
}
],
"reports": [
{
"allowEdit": false,
"id": "5234asdf-gbjasd-18943-10020-666saf32es0b1"
}
],
"identities": [
{
"username": "customer@email.com",
"roles": ["CUSTOMER"],
"CustomData": "0000007"
,
"datasets": [
"b4abcs-5xxx-4533-8fbhgg-123445b"
]
}
]
}
ADMIN:
Para esta regra, não será necessário o envio de dados por CustomData, pois a regra de acesso full já está sendo apontada.
{
"datasets": [
{
"id": "b4abcs-5xxx-4533-8fbhgg-123445b"
}
],
"reports": [
{
"allowEdit": false,
"id": "5234asdf-gbjasd-18943-10020-666saf32es0b1"
}
],
"identities": [
{
"username": "gerenteadmin@email.com",
"roles": ["ADMIN"],
"datasets": [
"b4abcs-5xxx-4533-8fbhgg-123445b"
]
}
]
}
Utilizando qualquer um dos corpos de solicitação acima, teremos a seguinte resposta:
{
"token": "H4sI....AAA=",
"tokenId": "49ae3742-54c0-4c29-af52-619ff93b5c80",
"expiration": "2028-07-29T17:58:19Z"
}
Concluindo, agora temos o que precisamos para que o report seja renderizado, URL de Inserção e Embed Token.
Caso queira realizar testes, poderá acessar o PBI Playground Developer e informar as informações obtidas.
Dica: caso esteja utilizando regras de RLS baseados em USERPRINCIPALNAME() ou USERNAME() recomenda-se acessar o playground em uma janela anônima do navegador, para que o mesmo não obtenha estas informações automaticamente da sua conta.
Obrigado por dedicar seu tempo para ler este artigo sobre Tokens do PowerBI Embedded e uso de RLS com CustomData. Espero que você tenha encontrado as informações aqui úteis e que possa aplicá-las em seus próprios projetos. Se você tiver alguma dúvida ou quiser compartilhar sua própria experiência com esses recursos, fique à vontade para entrar em contato ou deixar um comentário abaixo. Muito obrigado por sua atenção e espero que você volte!
“May the Force be with you”