Valtyr
Nos gustaría incrustar informes con RLS, pero empiezo a tener la sensación de que no es posible con Analysis Services (tanto Azure como en las instalaciones) usando una conexión en vivo en Power BI.
Comenzamos con el servicio de análisis local (conexión en vivo) pero eso no es compatible de acuerdo con el siguiente documento:
https://docs.microsoft.com/en-us/azure/power-bi-embedded/power-bi-embedded-connect-datasource
Por lo tanto, movimos los datos a Azure y ahora tenemos una conexión en vivo de Azure Analysis Service y nos gustaría integrarla con RLS.
Estamos teniendo problemas para implementar esto y en la siguiente página web hay una nota que dice que las conexiones en vivo de Analysis Services no son compatibles:
https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-embedded-rls/
¿Es este realmente el caso y, de ser así, cuándo podemos esperar integrar informes de RLS Power Bi con datos de Analysis Service (conexión en vivo)? ¿Está esto en la hoja de ruta?
Por cierto, estamos trabajando con grandes conjuntos de datos, por lo que usar la importación en lugar de la conexión en vivo no es realmente una opción para nosotros.
Valtyr
Finalmente conseguí que esto funcionara con PowerBi Embedding y RLS usando las siguientes instrucciones:
https://docs.microsoft.com/en-us/power-bi/developer/embedded-row-level-security#working-with-analysi…
Asegúrese de usar la función DAX de datos personalizados para filtrar los datos y también de agregar un usuario de Azure a la función:
=INS_TABLA[column] = Datos personalizados()
Usé el proyecto de muestra que se encuentra aquí:
https://docs.microsoft.com/en-us/power-bi/developer/embed-sample-for-customers#embed-your-content-us…
con la siguiente modificación:
// Generar token de inserción para informes sin identidades efectivas.
var rls = nueva identidad efectiva («xxxAzureUserName», nueva lista
generarTokenRequestParameters = new GenerateTokenRequest(accessLevel: «ver», identidades: nueva Lista
Espero que esto ayude
Valtyr
Finalmente conseguí que esto funcionara con PowerBi Embedding y RLS usando las siguientes instrucciones:
https://docs.microsoft.com/en-us/power-bi/developer/embedded-row-level-security#working-with-analysi…
Asegúrese de usar la función DAX de datos personalizados para filtrar los datos y también de agregar un usuario de Azure a la función:
=INS_TABLA[column] = Datos personalizados()
Usé el proyecto de muestra que se encuentra aquí:
https://docs.microsoft.com/en-us/power-bi/developer/embed-sample-for-customers#embed-your-content-us…
con la siguiente modificación:
// Generar token de inserción para informes sin identidades efectivas.
var rls = nueva identidad efectiva («xxxAzureUserName», nueva lista
generarTokenRequestParameters = new GenerateTokenRequest(accessLevel: «ver», identidades: nueva Lista
Espero que esto ayude
tommartens
En respuesta a Valtyr
Gracias @Valtyr,
por compartir tu solución.
Saludos,
Tomás
Rishabh-Maini
En respuesta a Valtyr
Hola @Valtyr,
He estado tratando de incrustar un informe powerbi basado en un modelo AAS también
Seguimos recibiendo el siguiente error:
Resultado
11:12:36:747 USUARIO_DEBUG [153]|DEBUG|Cuerpo: {«error»:{«code»:»InvalidRequest»,»message»:»La creación de un token de inserción para acceder al conjunto de datos *ID del conjunto de datos* requiere que se proporcione una identidad efectiva»}}
La modificación especificada en su comentario, ¿en qué archivo la agregó?
¿Y no usó la función Customdata() junto con ella?
¿Hay un código de muestra que pueda proporcionar con el que podamos hacer que esto funcione?
Realmente agradecería cualquier tipo de ayuda.
¡Gracias!
Matt Stannett
En respuesta a Rishabh-Maini
Suponiendo que está usando C#, a continuación se muestra una implementación que he usado para una implementación de páginas de Razor.
De ninguna manera es perfecto, pero funciona, espero que ayude
// CSPROJ
<PackageReference Include="Microsoft.AnalysisServices.NetCore.retail.amd64" Version="19.10.0-Preview" />
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.14.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.14.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="3.1.7" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.7.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.2.0" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.8" />
<PackageReference Include="Microsoft.PowerBI.Api" Version="3.14.0" />
// App Settings
"ActiveDirectoryUpn": {
"ClaimTypesToSearch": [
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"preferred_username"
]
}
// Reports.cshtml.cs
// _settingsType is an enum
public async Task OnGetAsync(Guid? reportId)
{
ClaimsPrincipal user = _httpContextAccessor.HttpContext.User;
List<Claim> claims = user.Claims.ToList();
IList<Report> reportsResult = await _reportRepository.GetAvailableReportsAsync(_settingsType);
Reports = new List<Report>(reportsResult);
string[] claimTypesToSearch = _activeDirectoryUpnSettings.Value.ClaimTypesToSearch;
// SECURITY : Don't do this unless we can secure things downstream
string upn = claims.Where(c => claimTypesToSearch.Contains(c.Type) && RegexUtilities.IsValidEmail(c.Value)).Select(c => c.Value).FirstOrDefault();
string claimsJson = JsonConvert.SerializeObject(GenerateDictionaryForUserClaims(claims));
if (reportId.HasValue)
{
SelectedReport = await _reportRepository.GetEmbeddedReportConfigAsync(reportId.Value, upn, claimsJson, _settingsType);
var identityNameId = user.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
var identityName = user.Claims.FirstOrDefault(x => x.Type == "preferred_username");
_telemetry.TrackEvent("ReportOpened", new Dictionary<string, string>
{
{ "report_Id", SelectedReport.Id },
{ "report_Name", SelectedReport.Name }
});
}
else
{
SelectedReport = await _reportRepository.GetEmbeddedReportConfigAsync(null, upn, claimsJson, _settingsType);
}
}
// ReportRepository.cs
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
public async Task<EmbeddedReportConfig> GetEmbeddedReportConfigAsync(Guid? reportId, string name, string claimsJson, SettingsTypeEnum settingsType)
{
PowerBiSettings powerBiSettings = GetPowerBiSettings(settingsType);
AzureToken azureToken = await _authenticationHandler.GetAzureTokenDataAsync(settingsType);
using (var powerBiClient = new PowerBIClient(new Uri(powerBiSettings.ApiUrl), azureToken.TokenCredentials))
{
List<string> roles = await GetDataFromAzureAnalysisServices(settingsType, name);
int assignedRolesCount = roles.Count;
string debugOutput = BuildDebugOutput(reportId, name, claimsJson, roles, assignedRolesCount);
if (!reportId.HasValue)
{
// Initial page load where no report is selected or the user has manually removed the report GUID from the URL
return GetEmbeddedReportConfig(null, null, 0, debugOutput);
}
else if (!roles.Any())
{
// A report is selected but the user has no roles
return GetEmbeddedReportConfig(new Report(reportId.Value), null, 0, debugOutput);
}
try
{
Report powerBiReport = await powerBiClient.Reports.GetReportAsync(powerBiSettings.WorkspaceId, reportId.Value);
// SECURITY : Is there a better way to do Effective Identity without passing through CustomData?
EffectiveIdentity rowLevelSecurityIdentity = new EffectiveIdentity(powerBiSettings.Username, roles: roles, datasets: new List<string> { powerBiReport.DatasetId }, customData: name);
GenerateTokenRequest powerBiTokenRequestParameters = new GenerateTokenRequest("View", powerBiReport.DatasetId, false, rowLevelSecurityIdentity);
EmbedToken powerBiTokenResponse = await powerBiClient.Reports.GenerateTokenInGroupAsync(powerBiSettings.WorkspaceId, powerBiReport.Id, powerBiTokenRequestParameters);
return GetEmbeddedReportConfig(powerBiReport, powerBiTokenResponse, assignedRolesCount, debugOutput);
}
catch (HttpOperationException ex)
{
//Bad Request
var content = ex.Response.Content;
Console.WriteLine(content);
throw;
}
}
}
private EmbeddedReportConfig GetEmbeddedReportConfig(Report powerBiReport, EmbedToken powerBiTokenResponse, int assignedRolesCount, string debugOuput)
{
return new EmbeddedReportConfig
{
Id = powerBiReport?.Id.ToString(),
Name = powerBiReport?.Name,
EmbedUrl = powerBiReport?.EmbedUrl,
AccessToken = powerBiTokenResponse?.Token,
AssignedRolesCount = assignedRolesCount,
DebugInformation = debugOuput
};
}
private async Task<List<string>> GetDataFromAzureAnalysisServices(SettingsTypeEnum settingsType, string upn)
{
AzureAnalysisServicesEndpointSettings settings = GetAzureAnalysisServicesEndpointSettings(settingsType);
string serverDomain = settings.ServerDomain;
string serverName = settings.ServerName;
// Use the trial database as a safe default
string databaseModel = settingsType == SettingsTypeEnum.Premium ? "PilotV1" : "PilotV2Demo";
string serverAddress = $"asazure://{serverDomain}/{serverName}";
// Used to be used in the authority URL
string tenantId = settings.TenantId;
string appId = settings.ApplicationId;
string appSecret = settings.AppSecret;
string authorityUrl = settings.AuthorityUrl;
AuthenticationContext authContext = new AuthenticationContext(authorityUrl);
// Config for OAuth client credentials
ClientCredential clientCred = new ClientCredential(appId, appSecret);
AuthenticationResult authenticationResult = await authContext.AcquireTokenAsync($"https://{serverDomain}", clientCred);
string connectionString = $"Provider=MSOLAP;Data Source={serverAddress};Initial Catalog={databaseModel};User ID=;Password={authenticationResult.AccessToken};Persist Security Info=True;Impersonation Level=Impersonate";
List<string> roles = new List<string>();
using (Server server = new Server())
{
server.Connect(connectionString);
// If your database isn't appearing here, then it is most likely because the AAS role which has the "Full Control" permission
// along a member entry for app:<app-registration-object-id>@<azure-active-directory-tenant-id> has been removed.
Database database = server.Databases.FindByName(databaseModel);
if (database == null)
{
return roles;
}
var modelRoles = database.Model.Roles;
List<RoleMapping> roleMappings = modelRoles.Select(r => new RoleMapping(r.Name, r.Members.Select(m => m.MemberName).ToList())).ToList();
roles = roleMappings.Where(g => g.Members.Contains(upn, StringComparer.InvariantCultureIgnoreCase)).Select(k => k.Name).ToList();
}
return roles;
}
Rishabh-Maini
En respuesta a Matt Stannett
Hola @MattStannett
¡Muchas gracias por el código!
En el siguiente:
// SEGURIDAD: ¿Hay una mejor manera de hacer una Identidad Efectiva sin pasar por CustomData?
Identidad Efectiva filaNivelSeguridadIdentidad = nueva Identidad Efectiva(powerBiSettings.Nombre de usuario, roles: roles, conjuntos de datos: nueva lista
GenerateTokenRequest powerBiTokenRequestParameters = new GenerateTokenRequest(«Ver», powerBiReport.DatasetId, false, rowLevelSecurityIdentity);
¿Qué valores de parámetros estoy pasando aquí?
powerBiSettings.Nombre de usuario
datos personalizados: nombre
Además, ¿está utilizando el filtro CUSOTMDATA() en los roles?
Matt Stannett
En respuesta a Rishabh-Maini
¡No hay problema @Rishabh-Maini!
Para powerBiSettings.Nombre de usuario Uso la dirección de correo electrónico de mi usuario maestro en Power BI.
Para nombre Utilizo el valor pasado a la función, que puede ver que es el arriba variable establecida en el OnGetAsync método.
si estoy usando DATOS PERSONALIZADOS para filtrar los roles en el lado AAS.
rg2018
En respuesta a Valtyr
Gracias por la publicacion. Tengo un escenario similar en el que, en modo incrustado, necesito mostrar el informe de PowerBi y Powerbi consume datos de los servicios de análisis de Azure. Necesito filtrar datos de los servicios de análisis según la regla RLS (ID de cuenta). No entiendo cómo ha especificado la función CustomeData(). ¿Puedes pasar alguna muestra? Gracias.
Valtyr
En respuesta a rg2018
Hola,
El método funciona así:
=NOMBRE DE LA TABLA[COLUMNNAME] = Datos personalizados()
En tu caso podría ser algo como esto:
=CUENTAS[ACCOUNTID] = Datos personalizados()
Espero que esto ayude 🙂
Matt Stannett
En respuesta a Valtyr
Estoy usando datos de PBI App Owns, Azure Analysis Services Live Connection y Azure Active Directory.
Para pasar a través de una identidad efectiva y aplicar RLS al informe resultante mediante un UPN y evitar el siguiente error
«La creación de un token de inserción para acceder al conjunto de datos xxxxxxxxxxxxxxxxxx requiere que el nombre de usuario de identidad efectivo sea idéntico al nombre principal de la persona que llama»
¿Necesito usar la función CustomData() y agregar un filtro de fila a mis roles en Azure Analysis Services para aplicar esto?
@Valtyr @nimrod @u02cm62 @Eric_Zhang
Matt Stannett
En respuesta a Matt Stannett
Finalmente resolví esto y publiqué mi solución en mi hilo de preguntas.
u02cm62
Lo tenemos funcionando para SSAS 2017 local, AppOwnsData, conexiones en vivo e integrado en Salesforce con una aplicación web de Azure.
SSAS Paas (Azure AS) sentí que aún no estaba listo para RLS, por lo que lo pospusimos. ¿Solo le preocupa Azure AS con AppOwnsData y conexiones en vivo?
jeffrey_b
En respuesta a u02cm62
Hola u02cm62,
En este momento, estoy intentando configurar RLS en Power BI Embedded (en un portal) usando SSAS local, AppOnwsData, conexión en vivo con un cubo multidimensional.
¿Podrías decir cómo configurarlo? Probé con CustomData() pero según este sitio, no es posible cuando no tiene Azure Analysis Services: https://docs.microsoft.com/nl-nl/power-bi/developer/embedded-row-level -security#on-premises-data-gat…:
Uso de la función CustomData
La característica CustomData solo funciona para modelos que se encuentran en Servicios de análisis de Azure, y solo funciona en Conéctate en vivo modo. a diferencia de usuarios y roles, la función de datos personalizados no se puede configurar dentro de un archivo .pbix. Al generar un token con la función de datos personalizados, debe tener un nombre de usuario.
Publiqué mi pregunta en línea, pero no obtuve respuestas. Es difícil encontrar información sobre cómo funciona esto.
Gracias por adelantado
Valtyr
En respuesta a u02cm62
@u02cm62
Actualmente, solo nos preocupa Azure AS con AppOwnsData y conexión en vivo, pero es bueno saber que funciona en las instalaciones. Probablemente tendremos que seguir ese camino hasta que Azure Live Connection sea totalmente compatible.
nimrod
En respuesta a Valtyr
Como mencioné en mi comentario anterior, pondremos en marcha el soporte de CustomData para AAS usando una conexión en vivo.
La función CustomData también se puede utilizar para RLS.
vizcondeoz
En respuesta a nimrod
Hola,
¿Alguna actualización sobre ETA cuando los datos personalizados serán compatibles con AAS?
nimrod
En respuesta a vizcondeoz
Ya es
https://powerbi.microsoft.com/en-us/blog/power-bi-developer-community-febrero-actualización/
nimrod
En respuesta a u02cm62
Hola,
PBIE admite RLS en conexión AS Live. Puede verlo aquí: https://docs.microsoft.com/en-us/power-bi/developer/embedded-row-level-security#working-with-analysi….
Además, admitimos el filtrado por roles predefinidos en AAS.
Y, lanzaremos dentro de un mes el soporte de filtrado por CustomData en AAS.
Valtyr
En respuesta a nimrod
@nimrod
Como se menciona en las limitaciones en el enlace que envió, esto solo es compatible con On-Premise:
-Las conexiones en vivo de Analysis Services son compatibles con los servidores locales.
¿Puede darnos alguna idea sobre cuándo será totalmente compatible con el servicio de análisis de Azure?
markus_x5
Tengo el mismo problema y pensé que estaba haciendo algo mal (la documentación no es excelente), pero aparentemente es una falta en el servicio. Como todos los demás en este hilo, también me encantaría obtener más información sobre planes futuros de apoyo.
Editar:
Creo una entrada de comentarios para este problema en feedback.azure.com, siéntase libre de votarla, de esa manera tal vez podamos llamar la atención sobre esto:
https://feedback.azure.com/forums/34192–general-feedback/suggestions/32984296-embed-rls-power-bi-re…
Valtyr
En respuesta a markus_x5
Escuché rumores vagos de que esto podría ser compatible en el primer trimestre de 2018. Me gustaría confirmarlo, pero no estoy seguro de dónde obtener una respuesta adecuada.