Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Aplique segurança em nível de coluna a colunas que contêm informações confidenciais. Proteger senhas, números de conta bancária, IDs governamentais, números de telefone ou endereços de email no nível da coluna.
Este artigo explica como os desenvolvedores podem trabalhar com recursos de segurança em nível de coluna usando o código e o SDK do Dataverse para .NET ou API Web. Você não precisa escrever código para usar esse recurso. Saiba como configurar a segurança em nível de coluna para controlar o acesso. Os desenvolvedores também devem entender como configurar a segurança em nível de coluna usando o Power Apps.
Descobrir quais colunas são protegidas
Detecte quais colunas são protegidas recuperando a definição da coluna e examinando a propriedade booleana AttributeMetadata.IsSecured.
Existem dois métodos para descobrir quais colunas são protegidas usando código. As seções a seguir descrevem estes métodos:
- Recuperar dados de coluna filtrados no IsSecured
- Recuperar o perfil FieldSecurityProfile para o Administrador do Sistema
Recuperar dados da coluna filtrados em IsSecured
Esse método consulta os metadados da organização para identificar colunas marcadas com a IsSecured propriedade definida como true. Todos têm acesso para exibir esses dados.
Saiba como consultar definições de esquema.
O arquivo CSV resultante contém duas colunas: Tabela e Coluna, representando os nomes de esquema das tabelas e suas colunas protegidas, respectivamente.
/// <summary>
/// Generates a CSV file containing the names of secured columns for all tables
/// in the organization.
/// </summary>
/// <remarks>This method queries the organization's metadata to identify columns
/// marked as secured (i.e., columns with the <c>IsSecured</c> property set to
/// <see langword="true"/>). The resulting CSV file contains two columns: "Table"
/// and "Column", representing the schema names of the tables and their secured
/// columns, respectively. <para> Ensure that the provided
/// <paramref name="filepath"/> is writable and that the user has appropriate
/// permissions to access the specified directory. </para></remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// retrieve metadata from the organization.</param>
/// <param name="filepath">The directory path where the CSV file will be saved.
/// Must be a valid and accessible file path.</param>
/// <param name="filename">The name of the CSV file to be created. Defaults to
/// "SecuredColumns.csv" if not specified.</param>
static internal void GetSecuredColumns(IOrganizationService service,
string filepath, string filename = "SecuredColumns.csv")
{
EntityQueryExpression query = new()
{
Properties = new MetadataPropertiesExpression(
"SchemaName",
"Attributes"),
Criteria = new MetadataFilterExpression(),
AttributeQuery = new()
{
Properties = new MetadataPropertiesExpression(
"SchemaName",
"AttributeTypeName"),
Criteria = new MetadataFilterExpression()
{
Conditions = {
{
new MetadataConditionExpression(
"IsSecured",
MetadataConditionOperator.Equals,
true)
}
}
}
}
};
RetrieveMetadataChangesRequest request = new()
{
Query = query
};
var response = (RetrieveMetadataChangesResponse)service.Execute(request);
// Create a StringBuilder to hold the CSV data
StringBuilder csvContent = new();
string[] columns = {
"Table",
"Column" };
// Add headers
csvContent.AppendLine(string.Join(",", columns));
foreach (var table in response.EntityMetadata)
{
foreach (var column in table.Attributes)
{
string[] values = {
table.SchemaName,
column.SchemaName
};
// Add values
csvContent.AppendLine(string.Join(",", values));
}
}
File.WriteAllText(
Path.Combine(filepath, filename),
csvContent.ToString());
}
Obter o perfil FieldSecurityProfile para Administrador do Sistema
Esse método consulta a tabela de permissões de campo do Dataverse para identificar colunas que o registro Field Security Profile (FieldSecurityProfile) com ID 572329c1-a042-4e22-be47-367c6374ea45 protege. Esse registro gerencia o acesso a colunas protegidas para administradores do sistema. Normalmente, somente os administradores do sistema têm o prvReadFieldPermission privilégio de recuperar esses dados.
O método estático GetSecuredColumnList retorna nomes de coluna totalmente qualificados no formato TableName.ColumnName, classificado em ordem alfabética.
/// <summary>
/// Retrieves a list of secured columns managed by the specified field security
/// profile.
/// </summary>
/// <remarks>This method queries the Dataverse field permission table to identify
/// columns that are secured by the field security profile with ID
/// <c>572329c1-a042-4e22-be47-367c6374ea45</c>. The returned list contains fully
/// qualified column names in the format <c>TableName.ColumnName</c>, sorted
/// alphabetically.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// interact with the Dataverse service.</param>
/// <returns>A sorted list of strings representing the fully qualified names of
/// secured columns.</returns>
/// <exception cref="Exception">Thrown if the calling user does not have read
/// access to the field permission table or if an error occurs while retrieving
/// field permissions.</exception>
static internal List<string> GetSecuredColumnList(IOrganizationService service)
{
QueryExpression query = new("fieldpermission")
{
ColumnSet = new ColumnSet("entityname", "attributelogicalname"),
Criteria = new FilterExpression(LogicalOperator.And)
{
Conditions =
{
// Field security profile with ID '572329c1-a042-4e22-be47-367c6374ea45'
// manages access for system administrators. It always contains
// references to each secured column
new ConditionExpression("fieldsecurityprofileid", ConditionOperator.Equal,
new Guid("572329c1-a042-4e22-be47-367c6374ea45"))
}
}
};
EntityCollection fieldPermissions;
try
{
fieldPermissions = service.RetrieveMultiple(query);
}
catch (FaultException<OrganizationServiceFault> ex)
{
if (ex.Detail.ErrorCode.Equals(-2147220960))
{
string message = "The calling user doesn't have read access to the fieldpermission table";
throw new Exception(message);
}
else
{
throw new Exception($"Dataverse error retrieving field permissions: {ex.Message}");
}
}
catch (Exception ex)
{
throw new Exception($"Error retrieving field permissions: {ex.Message}", ex);
}
List<string> values = [];
foreach (var fieldpermission in fieldPermissions.Entities)
{
string tableName = fieldpermission.GetAttributeValue<string>("entityname")!;
string columnName = fieldpermission.GetAttributeValue<string>("attributelogicalname")!;
values.Add($"{tableName}.{columnName}");
}
values.Sort();
return values;
}
Descobrir quais colunas você pode proteger
Não é possível proteger todas as colunas. Quando você habilita a segurança da coluna usando o Power Apps, a caixa de seleção Habilitar segurança de coluna é desabilitada para determinados campos. Você não precisa verificar manualmente cada coluna para descobrir se pode protegê-la. Escreva uma consulta para recuperar quais colunas você pode proteger.
Três propriedades Boolean AttributeMetadata controlam se você pode proteger qualquer coluna:
Quando todas essas propriedades são falsas, você não pode proteger a coluna. Algumas colunas só podem ser protegidas para uma ou duas das três operações: Create, Reade Update.
As consultas a seguir retornam esses dados para que você possa descobrir quais colunas em seu ambiente você pode proteger:
Esse método estático DumpColumnSecurityInfo recupera metadados sobre atributos de entidade, incluindo propriedades relacionadas à segurança, e grava as informações em um arquivo CSV. O arquivo de saída contém detalhes como se as colunas são protegidas, podem ser protegidas para operações de criação, atualização ou leitura e outros metadados relevantes.
/// <summary>
/// Exports column security information for all entities in the organization to a
/// CSV file.
/// </summary>
/// <remarks>This method retrieves metadata about entity attributes, including
/// security-related properties, and writes the information to a CSV file. The output
/// file contains details such as whether columns are secured, can be secured for
/// create, update, or read operations, and other relevant metadata.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// retrieve metadata from the organization.</param>
/// <param name="filepath">The directory path where the CSV file will be saved. This
/// must be a valid, writable directory.</param>
/// <param name="filename">The name of the CSV file to create. Defaults to
/// "ColumnSecurityInfo.csv" if not specified.</param>
static internal void DumpColumnSecurityInfo(IOrganizationService service,
string filepath, string filename = "ColumnSecurityInfo.csv")
{
EntityQueryExpression query = new()
{
Properties = new MetadataPropertiesExpression("SchemaName", "Attributes"),
Criteria = new MetadataFilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new MetadataConditionExpression(
"IsPrivate",
MetadataConditionOperator.Equals,
false),
}
},
AttributeQuery = new()
{
Properties = new MetadataPropertiesExpression(
"SchemaName",
"AttributeTypeName",
"IsPrimaryName",
"IsSecured",
"CanBeSecuredForCreate",
"CanBeSecuredForUpdate",
"CanBeSecuredForRead"),
Criteria = new MetadataFilterExpression()
{
Conditions = {
{ // Exclude Virtual columns
new MetadataConditionExpression(
"AttributeTypeName",
MetadataConditionOperator.NotEquals,
AttributeTypeDisplayName.VirtualType)
}
}
}
}
};
RetrieveMetadataChangesRequest request = new()
{
Query = query
};
var response = (RetrieveMetadataChangesResponse)service.Execute(request);
// Create a StringBuilder to hold the CSV data
StringBuilder csvContent = new();
string[] columns = {
"Column",
"Type",
"IsPrimaryName",
"IsSecured",
"CanBeSecuredForCreate",
"CanBeSecuredForUpdate",
"CanBeSecuredForRead" };
// Add headers
csvContent.AppendLine(string.Join(",", columns));
foreach (var table in response.EntityMetadata)
{
foreach (AttributeMetadata column in table.Attributes)
{
string[] values = {
$"{table.SchemaName}.{column.SchemaName}",
column.AttributeTypeName.Value,
column.IsPrimaryName?.ToString() ?? "False",
column.IsSecured?.ToString() ?? "False",
column.CanBeSecuredForCreate?.ToString() ?? "False",
column.CanBeSecuredForUpdate.ToString() ?? "False",
column.CanBeSecuredForRead.ToString() ?? "False"
};
// Add values
csvContent.AppendLine(string.Join(",", values));
}
}
File.WriteAllText(
Path.Combine(filepath, filename),
csvContent.ToString());
}
Proteger uma coluna com o uso de código
É mais fácil proteger uma coluna usando o Power Apps. Se você precisar automatizar a proteção de uma coluna, use o código para atualizar a definição da coluna para definir a propriedade AttributeMetadata.IsSecured , conforme mostrado nos exemplos a seguir:
Esse método estático SetColumnIsSecured recupera a definição atual da coluna especificada e atualiza seu status de segurança somente se o valor fornecido for diferente do valor atual. Se a coluna já estiver definida como o status de segurança especificado, o método não enviará uma solicitação de atualização.
/// <summary>
/// Updates the security status of a column in a Dataverse table.
/// </summary>
/// <remarks>This method retrieves the current definition of the specified column
/// and updates its security status only if the provided value differs from the
/// current value. If the column is already set to the specified security status,
/// no update request is sent.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// interact with the Dataverse service.</param>
/// <param name="tableLogicalName">The logical name of the table containing the
/// column to be updated. Cannot be null or empty.</param>
/// <param name="columnLogicalName">The logical name of the column whose security
/// status is to be updated. Cannot be null or empty.</param>
/// <param name="value">A <see langword="true"/> value indicates that the column
/// should be secured; otherwise, <see langword="false"/>.</param>
/// <param name="solutionUniqueName">The unique name of the solution in which the
/// column update should be applied. Cannot be null or empty.</param>
/// <exception cref="Exception">Thrown if an error occurs while retrieving or
/// updating the column definition.</exception>
static internal void SetColumnIsSecured(
IOrganizationService service,
string tableLogicalName,
string columnLogicalName,
bool value,
string solutionUniqueName)
{
// Update request requires the entire column definition,
// So retrieving that first
RetrieveAttributeRequest retrieveRequest = new()
{
EntityLogicalName = tableLogicalName,
LogicalName = columnLogicalName
};
AttributeMetadata columnDefinition;
try
{
var retrieveResponse = (RetrieveAttributeResponse)service.Execute(retrieveRequest);
columnDefinition = retrieveResponse.AttributeMetadata;
}
catch (Exception ex)
{
throw new Exception($"Error retrieving column definition: {ex.Message}", ex);
}
if (!columnDefinition.IsSecured.HasValue || columnDefinition.IsSecured.Value != value)
{
// Set the IsSecured property to value
columnDefinition.IsSecured = value;
UpdateAttributeRequest updateRequest = new()
{
EntityName = tableLogicalName,
Attribute = columnDefinition,
MergeLabels = true,
SolutionUniqueName = solutionUniqueName
};
try
{
service.Execute(updateRequest);
}
catch (Exception ex)
{
throw new Exception($"Error updating column definition: {ex.Message}", ex);
}
}
else
{
//Don't send a request to set the value to what it already is.
}
}
Fornecer acesso a colunas protegidas
Por padrão, quando você protege uma coluna, somente as pessoas que têm a função de segurança do administrador do sistema podem ler ou definir o valor. Um administrador do sistema pode fornecer a outros usuários acesso a colunas protegidas de duas maneiras:
- Gerenciar o acesso usando perfis de segurança de campo: use perfis de segurança de campo para dar acesso aos dados de coluna de todos os registros aos grupos.
- Compartilhar dados em campos protegidos: use o compartilhamento de campo para conceder a um principal específico ou a uma equipe acesso aos dados em uma coluna segura para um registro específico.
Gerenciar o acesso usando perfis de segurança de campo
Use essa abordagem quando você tiver diferentes grupos de usuários que precisam de diferentes níveis de acesso. Para obter um exemplo, consulte o exemplo de segurança em nível de coluna que descreve como proteger campos para diferentes usuários usando o centro de administração do Power Platform.
Para gerenciar o acesso usando código, crie registros Field Security Profile (FieldSecurityProfile) que associam principais (usuários e equipes) a registros de Permissão de Campo (FieldPermission). Esses registros controlam quais operações de dados podem ser executadas nessa coluna para qualquer registro.
Você pode associar usuários do sistema e equipes ao seu perfil de segurança de campo usando as relações systemuserprofiles_association e teamprofiles_association de muitos-para-muitos, respectivamente.
Associe permissões de campo aos perfis de segurança de campo por meio da lk_fieldpermission_fieldsecurityprofileid relação um-para-muitos. A tabela a seguir descreve colunas importantes da tabela de permissões de campo:
| Coluna | Tipo | DESCRIÇÃO |
|---|---|---|
FieldSecurityProfileId |
Busca | Refere-se ao perfil de segurança de campo ao qual essa permissão de campo se aplica. |
EntityName |
String | O nome lógico da tabela que contém a coluna protegida. |
AttributeLogicalName |
String | O nome lógico da coluna protegida. |
CanCreate |
Escolha | Se o acesso de criação é permitido. Veja opções de tipo de permissão de segurança para campo |
CanRead |
Escolha | Se o acesso de leitura é permitido. Ver opções de tipo de permissão de segurança de campo |
CanUpdate |
Escolha | Se o acesso à atualização é permitido. Veja as opções de tipo de permissão de segurança de campo |
CanReadUnmasked |
Escolha | Se um valor desmascarado pode ser recuperado quando CanRead é permitido. |
Opções de tipo de permissão de segurança de campo
As colunas de escolha CanCreate, CanRead e CanUpdate usam os valores definidos pela escolha global field_security_permission_type.
-
0Não permitido -
4Permitido
Observação
Não defina CanReadUnmasked a coluna, a menos que esteja usando o recurso de exibição de dados mascarados e queira permitir que um aplicativo retorne o valor desmascarado.
Compartilhar dados em campos protegidos
Crie registros de compartilhamento de campo (PrincipalObjectAttributeAccess) para compartilhar o acesso a um campo seguro para um registro específico com outra pessoa.
Observação
Conceitualmente, esse processo é semelhante à tabela PrincipalObjectAccess que gerencia o compartilhamento de registros. A diferença é que, com o compartilhamento de registros , você usa o GrantAccess, ModifyAccesse RevokeAccess as mensagens para adicionar, modificar e remover registros da PrincipalObjectAccess tabela.
Saiba mais sobre como compartilhar registros
Com o compartilhamento de campo, use a PrincipalObjectAttributeAccess tabela para conceder, modificar e revogar o acesso a campos usando operações de criação, atualização e exclusão em uma linha de tabela.
A PrincipalObjectAttributeAccess tabela tem estas colunas:
| Coluna | Tipo | DESCRIÇÃO |
|---|---|---|
AttributeId |
Guid | O AttributeMetadata.MetadataId da coluna protegida. |
ObjectId |
Busca | Uma referência ao registro que contém a coluna protegida. |
PrincipalId |
Busca | Uma referência ao principal (usuário ou equipe) a quem você está concedendo acesso. |
ReadAccess |
Bool | Se conceder acesso de leitura aos dados de campo |
UpdateAccess |
Bool | Se deseja conceder permissão para atualizar os dados de campo |
Obtendo AttributeId de coluna
A PrincipalObjectAttributeAccess.AttributeId coluna usa AttributeMetadata.MetadataId em vez do nome lógico da coluna. Você precisa recuperar esse valor dos metadados. Se o aplicativo tiver um cache de metadados, você poderá incluir esses dados e acessá-los conforme necessário.
Exemplo de recuperação da coluna AttributeId
Este exemplo mostra como obter o valor AttributeMetadata.MetadataId necessário para definir o valor da PrincipalObjectAttributeAccess.AttributeId coluna.
Os exemplos do SDK para .NET de conceder acesso à coluna, modificar acesso à coluna e revogar acesso à coluna utilizam o método estático RetrieveColumnId para recuperar o valor AttributeMetadata.MetadataId usado na coluna PrincipalObjectAttributeAccess.AttributeId.
/// <summary>
/// Retrieves the unique identifier (MetadataId) of a column in a specified
/// Dataverse table.
/// </summary>
/// <remarks>
/// This method queries the organization's metadata to locate the specified column
/// within the given table and returns its MetadataId. If the table or column is
/// not found, an exception is thrown.
/// </remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// retrieve metadata from the organization.</param>
/// <param name="tableLogicalName">The logical name of the table containing the
/// column. Must not be null or empty.</param>
/// <param name="columnLogicalName">The logical name of the column whose MetadataId
/// is to be retrieved. Must not be null or empty.</param>
/// <returns>The <see cref="Guid"/> representing the MetadataId of the specified
/// column.</returns>
/// <exception cref="Exception">Thrown if the table or column is not found in the
/// metadata.</exception>
private static Guid RetrieveColumnId(
IOrganizationService service,
string tableLogicalName,
string columnLogicalName)
{
EntityQueryExpression query = new()
{
Properties = new MetadataPropertiesExpression("Attributes"),
Criteria = new MetadataFilterExpression(filterOperator: LogicalOperator.Or)
{
Conditions = {
{
new MetadataConditionExpression(
propertyName:"LogicalName",
conditionOperator: MetadataConditionOperator.Equals,
value:tableLogicalName)
}
},
},
AttributeQuery = new AttributeQueryExpression
{
Properties = new MetadataPropertiesExpression("MetadataId"),
Criteria = new MetadataFilterExpression(filterOperator: LogicalOperator.And)
{
Conditions = {
{
new MetadataConditionExpression(
propertyName:"LogicalName",
conditionOperator: MetadataConditionOperator.Equals,
value:columnLogicalName)
}
}
}
}
};
RetrieveMetadataChangesRequest request = new()
{
Query = query
};
var response = (RetrieveMetadataChangesResponse)service.Execute(request);
Guid columnId;
if (response.EntityMetadata.Count == 1)
{
if (response.EntityMetadata[0].Attributes.Length == 1)
{
// Nullable property will not be null when retrieved. It is set by the system.
columnId = response.EntityMetadata[0].Attributes[0].MetadataId!.Value;
}
else
{
throw new Exception($"Column {columnLogicalName} not found in {tableLogicalName}.");
}
}
else
{
throw new Exception($"Table {tableLogicalName} not found");
}
return columnId;
}
Exemplo de concessão de acesso à coluna
Esses exemplos criam um novo registro de compartilhamento de campo (PrincipalObjectAttributeAccess) para compartilhar o acesso ao campo especificado.
Esse método permite compartilhar permissões de leitura e/ou atualização para uma coluna segura em uma tabela do Dataverse com um principal específico (usuário ou equipe). A coluna deve ser configurada como um campo protegido no Dataverse.
Este exemplo depende da RetrieveColumnId função de exemplo encontrada no exemplo de AttributeId da coluna Retrieve.
/// <summary>
/// Grants access to a secured column for a specified principal in Dataverse.
/// </summary>
/// <remarks>This method allows you to share read and/or update permissions for a
/// secured column in a Dataverse table with a specific principal (user or team).
/// The column must be configured as a secured field in Dataverse.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// interact with Dataverse.</param>
/// <param name="record">A reference to the record (entity instance) containing the
/// secured column.</param>
/// <param name="columnLogicalName">The logical name of the secured column to grant
/// access to.</param>
/// <param name="principal">A reference to the principal (user or team) to whom
/// access is being granted.</param>
/// <param name="readAccess"><see langword="true"/> to grant read access to the
/// secured column; otherwise, <see langword="false"/>.</param>
/// <param name="updateAccess"><see langword="true"/> to grant update access to the
/// secured column; otherwise, <see langword="false"/>.</param>
/// <exception cref="Exception">Thrown if the column has already been shared or if
/// an error occurs during the operation.</exception>
static internal void GrantColumnAccess(
IOrganizationService service,
EntityReference record,
string columnLogicalName,
EntityReference principal,
bool readAccess,
bool updateAccess)
{
// This information should come from cached metadata,
// but for this sample it is retrieved each time.
Guid columnId = RetrieveColumnId(
service: service,
tableLogicalName: record.LogicalName,
columnLogicalName: columnLogicalName);
// https://learn.microsoft.com/power-apps/developer/data-platform/reference/entities/principalobjectattributeaccess
Entity poaa = new("principalobjectattributeaccess")
{
//Unique identifier of the shared secured field
["attributeid"] = columnId,
//Unique identifier of the entity instance with shared secured field
["objectid"] = record,
//Unique identifier of the principal to which secured field is shared
["principalid"] = principal,
// Read permission for secured field instance
["readaccess"] = readAccess,
//Update permission for secured field instance
["updateaccess"] = updateAccess
};
try
{
service.Create(poaa);
}
catch (FaultException<OrganizationServiceFault> ex)
{
if (ex.Detail.ErrorCode.Equals(-2147158773))
{
throw new Exception("The column has already been shared");
}
throw new Exception($"Dataverse error in GrantColumnAccess: {ex.Message}");
}
catch (Exception ex)
{
throw new Exception($"Error in GrantColumnAccess: {ex.Message}");
}
}
Modificar o exemplo de acesso à coluna
Esses exemplos recuperam e atualizam um registro existente de Compartilhamento de Campo (PrincipalObjectAttributeAccess) para modificar o acesso ao campo especificado.
Este exemplo depende da RetrieveColumnId função de exemplo encontrada no exemplo de AttributeId da coluna Retrieve.
/// <summary>
/// Modifies access permissions for a secure column in a table for a specified
/// principal.
/// </summary>
/// <remarks>This method updates or creates a record in the
/// PrincipalObjectAttributeAccess table to reflect the specified access
/// permissions. If no matching record is found, an exception is thrown.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// interact with the organization service.</param>
/// <param name="record">An <see cref="EntityReference"/> representing the record
/// containing the secure column.</param>
/// <param name="columnLogicalName">The logical name of the secure column whose
/// access permissions are being modified.</param>
/// <param name="principal">An <see cref="EntityReference"/> representing the
/// principal (user or team) for whom access permissions are being
/// modified.</param>
/// <param name="readAccess">A <see langword="bool"/> indicating whether read
/// access to the secure column should be granted (<see langword="true"/>) or
/// revoked (<see langword="false"/>).</param>
/// <param name="updateAccess">A <see langword="bool"/> indicating whether update
/// access to the secure column should be granted (<see langword="true"/>) or
/// revoked (<see langword="false"/>).</param>
/// <exception cref="Exception">Thrown if no matching
/// PrincipalObjectAttributeAccess record is found for the specified column,
/// record, and principal.</exception>
static internal void ModifyColumnAccess(
IOrganizationService service,
EntityReference record,
string columnLogicalName,
EntityReference principal,
bool readAccess,
bool updateAccess)
{
// This information should come from cached metadata,
// but for this sample it is retrieved each time.
Guid columnId = RetrieveColumnId(
service: service,
tableLogicalName: record.LogicalName,
columnLogicalName: columnLogicalName);
// Retrieve the record
QueryExpression query = new("principalobjectattributeaccess")
{
ColumnSet = new ColumnSet(
"principalobjectattributeaccessid",
"readaccess",
"updateaccess"),
Criteria = new FilterExpression(LogicalOperator.And)
{
// There can only be one record or zero records matching these criteria.
Conditions = {
{
new ConditionExpression(
attributeName:"attributeid",
conditionOperator: ConditionOperator.Equal,
value:columnId)
},
{
new ConditionExpression(
attributeName:"objectid",
conditionOperator: ConditionOperator.Equal,
value:record.Id)
},
{
new ConditionExpression(
attributeName:"principalid",
conditionOperator: ConditionOperator.Equal,
value:principal.Id)
},
{
new ConditionExpression(
attributeName:"principalidtype",
conditionOperator: ConditionOperator.Equal,
value:principal.LogicalName)
}
}
}
};
EntityCollection queryResults = service.RetrieveMultiple(query);
if (queryResults.Entities.Count == 1)
{
// Update the record that granted access to the secure column
Entity retrievedPOAARecord = queryResults.Entities[0];
// Get the current values and only update if different
bool currentRead = retrievedPOAARecord.GetAttributeValue<bool>("readaccess");
bool currentUpdate = retrievedPOAARecord.GetAttributeValue<bool>("updateaccess");
Entity POAAForUpdate = new("principalobjectattributeaccess", retrievedPOAARecord.Id);
if (currentRead != readAccess)
{
POAAForUpdate.Attributes.Add("readaccess", readAccess);
}
if (currentUpdate != updateAccess)
{
POAAForUpdate.Attributes.Add("updateaccess", updateAccess);
}
// Don't update if nothing there is nothing to change
if (POAAForUpdate.Attributes.Count > 0)
{
// Update the principalobjectattributeaccess record
service.Update(POAAForUpdate);
}
}
else
{
throw new Exception("No matching PrincipalObjectAttributeAccess record found.");
}
}
Exemplo de revogação de acesso à coluna
Esses exemplos recuperam e excluem um registro existente de Compartilhamento de Campo (PrincipalObjectAttributeAccess) para revogar o acesso ao campo especificado.
Este exemplo depende da RetrieveColumnId função de exemplo encontrada no exemplo de AttributeId da coluna Retrieve.
/// <summary>
/// Revokes access to a secure column for a specified principal in a given record.
/// </summary>
/// <remarks>This method removes the access granted to a secure column for the
/// specified principal. If no matching access record is found, an exception is
/// thrown.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// interact with the Dataverse service.</param>
/// <param name="record">An <see cref="EntityReference"/> representing the record
/// containing the secure column.</param>
/// <param name="columnLogicalName">The logical name of the secure column for which
/// access is being revoked.</param>
/// <param name="principal">An <see cref="EntityReference"/> representing the
/// principal (user or team) whose access to the secure column is being
/// revoked.</param>
/// <exception cref="Exception">Thrown if no matching
/// PrincipalObjectAttributeAccess record is found for the specified column,
/// record, and principal.</exception>
internal static void RevokeColumnAccess(IOrganizationService service,
EntityReference record,
string columnLogicalName,
EntityReference principal)
{
// This information should come from cached metadata,
// but for this sample it is retrieved each time.
Guid columnId = RetrieveColumnId(
service: service,
tableLogicalName: record.LogicalName,
columnLogicalName: columnLogicalName);
QueryExpression query = new("principalobjectattributeaccess")
{
ColumnSet = new ColumnSet("principalobjectattributeaccessid"),
Criteria = new FilterExpression(LogicalOperator.And)
{
// These conditions return one or zero records
Conditions = {
{
new ConditionExpression(
attributeName:"attributeid",
conditionOperator: ConditionOperator.Equal,
value:columnId)
},
{
new ConditionExpression(
attributeName:"objectid",
conditionOperator: ConditionOperator.Equal,
value:record.Id)
},
{
new ConditionExpression(
attributeName:"principalid",
conditionOperator: ConditionOperator.Equal,
value:principal.Id)
},
{
new ConditionExpression(
attributeName:"principalidtype",
conditionOperator: ConditionOperator.Equal,
value:principal.LogicalName)
}
}
}
};
EntityCollection queryResults = service.RetrieveMultiple(query);
if (queryResults.Entities.Count == 1)
{
// Delete the record that granted access to the secure column
service.Delete("principalobjectattributeaccess", queryResults.Entities[0].Id);
}
else
{
throw new Exception("No matching PrincipalObjectAttributeAccess record found.");
}
}
Exibir dados mascarados
O comportamento da API padrão ao retornar um valor para uma coluna protegida é não retornar dados. O aplicativo de chamada não pode distinguir entre um valor protegido e um valor nulo.
Agora há um recurso de visualização que você pode usar para especificar que um valor de cadeia de caracteres é retornado quando os dados existem. Essa cadeia de caracteres pode ofuscar totalmente o valor ou mostrar partes dos dados, dependendo das regras de mascaramento definidas. Dessa forma, o aplicativo pode gerenciar melhor dados confidenciais.
Com esse recurso, você pode configurar registros de Permissão de Campo (FieldPermission) para criar perfis de segurança de campo que permitem que os aplicativos enviem solicitações para recuperar registros com o mascaramento removido para que os dados possam ser mostrados em circunstâncias controladas. Saiba mais sobre como recuperar dados desmascarados
Criar uma regra de mascaramento seguro
Cada coluna que exibe dados mascarados precisa se referir a uma linha de tabela Regra de Mascaramento Protegida (MaskingRule). Você pode criar regras de mascaramento seguro no Power Apps e adicioná-las à sua solução ou usar qualquer uma das regras existentes.
Crie registros de tabela de Coluna de Máscara Protegida (AttributeMaskingRule) para especificar qual regra de mascaramento uma coluna segura deve usar.
O diagrama a seguir descreve estas tabelas:
Colunas de regra de mascaramento protegidas
A tabela Regra de Máscara Protegida (MaskingRule) tem estas colunas editáveis:
| Coluna | Tipo | DESCRIÇÃO |
|---|---|---|
Name |
String | O nome exclusivo da regra de mascaramento protegida. |
Description |
String | Descrição da regra de mascaramento segura. |
DisplayName |
String | O nome de exibição da regra de mascaramento protegida. |
MaskedCharacter |
String | Caractere usado para mascarar. |
RegularExpression |
String | Expressão regular em C#. |
IsCustomizable |
BooleanManagedProperty | Informações que especificam se esse componente pode ser personalizado. Saiba mais sobre as propriedades gerenciadas |
RichTestData |
String | Defina dados de teste de rich text para testar essa regra de mascaramento protegida. |
MaskedRichTestData |
String |
RichTestData dados de coluna avaliados por essa regra de mascaramento segura. |
TestData |
String | Defina dados de teste para testar essa regra de mascaramento protegida. |
MaskedTestData |
String |
TestData dados de coluna avaliados por uma regra de mascaramento segura. |
Observação
As colunas RichTestData, MaskedRichTestData, TestData e MaskedTestData existem para dar suporte à experiência de testar regras de mascaramento no Power Apps.
Saiba mais sobre como criar regras de mascaramento.
Colunas de máscara protegidas
A tabela Coluna de Máscara Protegida (AttributeMaskingRule) tem estas colunas graváveis:
| Coluna | Tipo | DESCRIÇÃO |
|---|---|---|
AttributeLogicalName |
String | Nome lógico da coluna para a qual a regra de mascaramento protegida é usada. |
EntityName |
String | Nome lógico da tabela que contém a coluna. |
MaskingRuleId |
Busca | A regra de mascaramento usada pela coluna |
UniqueName |
String | O nome exclusivo da coluna de mascaramento protegida. |
IsCustomizable |
BooleanManagedProperty | Informações que especificam se esse componente pode ser personalizado. Saiba mais sobre as propriedades gerenciadas |
Recuperar dados desmascarados
Quando um registro de Permissão de Campo (FieldPermission) tiver o status de
A CanReadUnmasked coluna dá suporte às seguintes opções definidas pela opção global field_security_permission_readunmasked.
| Value | Etiqueta | DESCRIÇÃO |
|---|---|---|
| 0 | Não permitidos | O valor padrão. Se não houver nenhum AttributeMaskingRule para a coluna, você não poderá definir nenhum outro valor. |
| 1 | Um registro | Os dados desmascarados podem ser retornados usando apenas uma Retrieve operação. |
| 3 | Todos os registros | Os dados desmascarados podem ser retornados usando Retrieve e RetrieveMultiple operações. |
Recuperar exemplo de dados desmascarados
Os exemplos a seguir mostram como usar o UnMaskedData parâmetro opcional para solicitar que o valor desmascarado seja retornado quando a configuração da permissão de campo permitir.
O GetUnmaskedExampleRows exemplo retorna valores sem máscara para as colunas solicitadas em que o valor da permissão de campo CanReadUnmasked é definido como Todos os Registros porque o parâmetro opcional UnMaskedData é adicionado à solicitação RetrieveMultiple.
Esse método consulta a sample_example tabela e recupera colunas específicas, incluindo dados confidenciais, como ID do governo e data de nascimento. Os resultados da consulta são ordenados pela sample_name coluna em ordem decrescente.
/// <summary>
/// Retrieves a collection of example entities with unmasked data.
/// </summary>
/// <remarks>This method queries the "sample_example" entity and retrieves specific
/// columns, including sensitive data such as government ID and date of birth. The
/// query results are ordered by the "sample_name" column in descending order. The
/// method uses the "UnMaskedData" optional parameter to ensure that sensitive data
/// is returned unmasked. For more information on optional parameters, see <see
/// href="https://learn.microsoft.com/power-apps/developer/data-platform/optional-parameters">Optional
/// Parameters in Dataverse</see>.</remarks>
/// <param name="service">The <see cref="IOrganizationService"/> instance used to
/// execute the query.</param>
/// <returns>An <see cref="EntityCollection"/> containing the retrieved entities.
/// The collection includes unmasked data for the specified columns.</returns>
internal static EntityCollection GetUnmaskedExampleRows(IOrganizationService service)
{
QueryExpression query = new("sample_example")
{
ColumnSet = new ColumnSet(
"sample_name",
"sample_email",
"sample_governmentid",
"sample_telephonenumber",
"sample_dateofbirth"),
Criteria = new FilterExpression(),
Orders = {
{
new OrderExpression(
"sample_name",
OrderType.Descending)
}
}
};
RetrieveMultipleRequest request = new()
{
Query = query,
// This example uses 'UnMaskedData' as an optional parameter
// https://learn.microsoft.com/power-apps/developer/data-platform/optional-parameters
["UnMaskedData"] = true
};
var response = (RetrieveMultipleResponse)service.Execute(request);
return response.EntityCollection;
}
Artigos relacionados
Segurança e acesso a dados
Compartilhamento e atribuição
Exemplo: segurança em nível de coluna usando o SDK do Dataverse para .NET
Exemplo: segurança em nível de coluna usando a API Web do Dataverse (PowerShell)