Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Appliquez la sécurité au niveau des colonnes qui contiennent des informations sensibles. Mots de passe sécurisés, numéros de compte bancaire, ID gouvernementaux, numéros de téléphone ou adresses e-mail au niveau de la colonne.
Cet article explique comment les développeurs peuvent utiliser des fonctionnalités de sécurité au niveau des colonnes à l’aide du code et du Kit de développement logiciel (SDK) Dataverse pour .NET ou l’API web. Nul besoin d’écrire de code pour utiliser cette fonctionnalité. Découvrez comment configurer la sécurité au niveau de la colonne pour contrôler l’accès. Les développeurs doivent également comprendre comment configurer la sécurité au niveau des colonnes à l’aide de Power Apps.
Découvrir quelles colonnes sont sécurisées
Détectez quelles colonnes sont sécurisées en récupérant la définition de la colonne et en examinant la propriété booléenne AttributeMetadata.IsSecured.
Deux méthodes existent pour découvrir quelles colonnes sont sécurisées à l’aide du code. Les sections suivantes décrivent ces méthodes :
- Récupérer les données de colonne filtrées sur IsSecured
- Récupérer FieldSecurityProfile pour l’administrateur système
Récupérer les données de colonne filtrées sur IsSecured
Cette méthode interroge les métadonnées de l’organisation pour identifier les colonnes marquées avec la propriété IsSecured définie sur true. Chacun a accès à ces données.
Découvrez comment interroger des définitions de schéma.
Le fichier CSV qui en résulte contient deux colonnes : Table et Colonne, représentant respectivement les noms de schéma des tables et leurs colonnes sécurisées.
/// <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());
}
Récupérer le FieldSecurityProfile pour le rôle d’administrateur système
Cette méthode interroge la table des autorisations de champ Dataverse pour identifier les colonnes qui sont sécurisées par l’enregistrement du profil de sécurité du champ (FieldSecurityProfile) avec un ID 572329c1-a042-4e22-be47-367c6374ea45. Cet enregistrement gère l’accès aux colonnes sécurisées pour les administrateurs système. En règle générale, seuls les administrateurs système ont le privilège prvReadFieldPermission de récupérer ces données.
La méthode GetSecuredColumnList statique renvoie des noms de colonne complets dans le format TableName.ColumnName, triés par ordre alphabétique.
/// <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;
}
Découvrir les colonnes que vous pouvez sécuriser
Vous ne pouvez pas sécuriser toutes les colonnes. Lorsque vous activez la sécurité des colonnes à l’aide de Power Apps, la case à cocher Activer la sécurité des colonnes est désactivée pour certains champs. Vous n’avez pas besoin de vérifier manuellement chaque colonne pour savoir si vous pouvez la sécuriser. Écrivez une requête pour récupérer les colonnes que vous pouvez sécuriser.
Trois propriétés booléennes AttributeMetadata contrôlent si vous pouvez sécuriser n’importe quelle colonne :
Lorsque toutes ces propriétés sont fausses, vous ne pouvez pas sécuriser la colonne. Certaines colonnes peuvent n’être sécurisées que pour une ou deux des trois opérations : Create, Read, et Update.
Les requêtes suivantes retournent ces données pour vous permettre de découvrir les colonnes de votre environnement que vous pouvez sécuriser :
Cette méthode statique DumpColumnSecurityInfo récupère les métadonnées relatives aux attributs d’entité, y compris les propriétés liées à la sécurité, et écrit les informations dans un fichier CSV. Le fichier de sortie contient des détails tels que si les colonnes sont sécurisées, peuvent être sécurisées pour les opérations de création, de mise à jour ou de lecture, et d’autres métadonnées pertinentes.
/// <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());
}
Sécuriser une colonne avec du code
Il est plus simple de sécuriser une colonne à l’aide de Power Apps. Si vous devez automatiser la sécurisation d’une colonne, utilisez du code pour mettre à jour la définition de colonne pour définir la propriété AttributeMetadata.IsSecured , comme indiqué dans les exemples suivants :
Cette méthode SetColumnIsSecured statique récupère la définition actuelle de la colonne spécifiée et met à jour son état de sécurité uniquement si la valeur fournie diffère de la valeur actuelle. Si la colonne est déjà définie sur l’état de sécurité spécifié, la méthode n’envoie pas de demande de mise à jour.
/// <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.
}
}
Fournir l’accès aux colonnes sécurisées
Par défaut, lorsque vous sécurisez une colonne, seules les personnes qui ont le rôle de sécurité administrateur système peuvent lire ou définir la valeur. Un administrateur système peut fournir à d’autres utilisateurs l’accès aux colonnes sécurisées de deux manières :
- Gérez l’accès à l’aide de profils de sécurité de champ : utilisez des profils de sécurité de champ pour accorder l’accès aux données de colonne pour tous les enregistrements à des groupes.
- Partager des données dans des champs sécurisés : utilisez le partage de champs pour donner à un principal ou à une équipe spécifique l’accès aux données d’une colonne sécurisée pour un enregistrement spécifique.
Gérer l’accès à l’aide de profils de sécurité de champ
Utilisez cette approche lorsque vous avez différents groupes d’utilisateurs qui ont besoin de différents niveaux d’accès. Pour obtenir un exemple, consultez l’exemple de sécurité au niveau des colonnes qui décrit comment sécuriser des champs pour différents utilisateurs à l’aide du Centre d’administration Power Platform.
Pour gérer l'accès à l'aide du code, créez des enregistrements Profil de sécurité de champ (FieldSecurityProfile) qui associent des utilisateurs et des équipes à des enregistrements Autorisation de champ (FieldPermission). Ces enregistrements contrôlent les opérations de données qui peuvent être effectuées sur cette colonne pour n’importe quel enregistrement.
Vous pouvez associer des utilisateurs système et des équipes à votre profil de sécurité de champ à l’aide des relations plusieurs-à-plusieurs systemuserprofiles_association et teamprofiles_association respectivement.
Associez les autorisations de champ aux profils de sécurité de champ à l’aide de la lk_fieldpermission_fieldsecurityprofileidrelation un-à-plusieurs. Le tableau suivant décrit les colonnes importantes de la table d’autorisation de champ :
| Colonne | Type | Description |
|---|---|---|
FieldSecurityProfileId |
Recherche | Fait référence au profil de sécurité de champ auquel s’applique cette autorisation de champ. |
EntityName |
Chaîne | Nom logique de la table contenant la colonne sécurisée. |
AttributeLogicalName |
chaîne | Nom logique de la colonne sécurisée. |
CanCreate |
Option | Si l'accès à la fonctionnalité de création est autorisé. Voir Options de type d’autorisation de sécurité pour les champs |
CanRead |
Choix | Si l’accès en lecture est autorisé. Voir Options de type d'autorisation pour la sécurité des champs |
CanUpdate |
Choix | Indique si l’accès à la mise à jour est autorisé. Voir Options de type de permission de sécurité de champ |
CanReadUnmasked |
Option | Indique si une valeur non masquée peut être récupérée quand CanRead est autorisée. |
Options du type d’autorisation de sécurité de champ
Les colonnes de choix CanCreate, CanRead, et CanUpdate utilisent les valeurs définies par le choix global field_security_permission_type :
-
0Pas autorisé -
4Autorisé
Note
Ne définissez pas la colonne CanReadUnmasked, sauf si vous utilisez la fonctionnalité Affichage des données masquées et que vous souhaitez activer une application pour qu’elle renvoie la valeur non masquée.
Partager les données dans les champs sécurisés
Créez des enregistrements de partage de champ (PrincipalObjectAttributeAccess) pour partager l’accès à un champ sécurisé pour un enregistrement spécifique avec quelqu’un d’autre.
Note
Conceptuellement, ce processus est similaire à la table PrincipalObjectAccess qui gère le partage des enregistrements. La différence réside dans le fait qu’avec le partage d’enregistrements, vous utilisez les messages GrantAccess, ModifyAccess, et RevokeAccess pour ajouter, modifier et supprimer des enregistrements de la table PrincipalObjectAccess.
En savoir plus sur le partage des enregistrements
Avec le partage de champ, utilisez la table pour accorder, modifier et révoquer l’accès PrincipalObjectAttributeAccess aux champs à l’aide des opérations de création, de mise à jour et de suppression sur une ligne de table.
La table PrincipalObjectAttributeAccess a les colonnes suivantes :
| Colonne | Type | Description |
|---|---|---|
AttributeId |
Guid | Le champ AttributeMetadata.MetadataId de la colonne sécurisée. |
ObjectId |
Recherche | Référence à l’enregistrement qui contient la colonne sécurisée. |
PrincipalId |
Recherche | Référence au principal (utilisateur ou équipe) auquel vous accordez l’accès. |
ReadAccess |
Bool | Accorder ou non un accès en lecture aux données de champ |
UpdateAccess |
Bool | Indique s’il faut accorder ou non l’accès de mise à jour aux données du champ |
Obtention de l'ID d'attribut pour une colonne
La colonne PrincipalObjectAttributeAccess.AttributeId utilise le champ AttributeMetadata.MetadataId plutôt que le nom logique de la colonne. Vous devez récupérer cette valeur à partir des métadonnées. Si votre application dispose d’un cache de métadonnées, vous pouvez inclure ces données et y accéder selon vos besoins.
Exemple pour récupérer l'AttributeId de colonne
Cet exemple montre comment obtenir la valeur valeur AttributeMetadata.MetadataId dont vous avez besoin pour définir la valeur de colonne PrincipalObjectAttributeAccess.AttributeId.
Les exemples SDK for .NET Accorder l’accès à la colonne, Modifier l’accès à la colonne et Révoquer l’accès à la colonne utilisent la méthode RetrieveColumnId statique pour récupérer la valeur AttributeMetadata.MetadataId utilisée dans la colonne 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;
}
En savoir plus sur l’interrogation des définitions de schéma
Exemple d’octroi d’accès à la colonne
Ces exemples créent un enregistrement de partage de champ (PrincipalObjectAttributeAccess) pour partager l’accès au champ spécifié.
Cette méthode vous permet de partager les autorisations de lecture et/ou de mise à jour d’une colonne sécurisée d’une table Dataverse avec un principal spécifique (utilisateur ou équipe). La colonne doit être configurée en tant que champ sécurisé dans Dataverse.
Cet exemple dépend de l’exemple de fonction RetrieveColumnId trouvé dans l’exemple Récupérer l’exemple de la colonne AttributeId.
/// <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}");
}
}
Exemple de modification de l’accès aux colonnes
Ces exemples récupèrent et mettent à jour un enregistrement de partage de champ (PrincipalObjectAttributeAccess) existant pour modifier l’accès au champ spécifié.
Cet exemple dépend de l’exemple de fonction RetrieveColumnId trouvé dans l’exemple Récupérer l’exemple de la colonne AttributeId.
/// <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.");
}
}
Exemple de révocation de l’accès à la colonne
Ces exemples récupèrent et suppriment un enregistrement de partage de champ (PrincipalObjectAttributeAccess) existant pour révoquer l’accès au champ spécifié.
Cet exemple dépend de l’exemple de fonction RetrieveColumnId trouvé dans l’exemple Récupérer l’exemple de la colonne AttributeId.
/// <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.");
}
}
Afficher les données masquées
Le comportement par défaut de l’API lors du renvoi d’une valeur pour une colonne sécurisée est de ne renvoyer aucune donnée. L’application appelante ne peut pas faire la distinction entre une valeur sécurisée et une valeur nulle.
Il existe désormais une fonctionnalité d’évaluation que vous pouvez utiliser pour spécifier qu’une valeur de chaîne est renvoyée lorsque des données existent. Cette chaîne peut totalement obscurcir la valeur ou afficher des parties des données en fonction des règles de masquage que vous définissez. De cette façon, l’application peut mieux gérer les données sensibles.
Grâce à cette fonctionnalité, vous pouvez configurer des enregistrements d’autorisation de champ (FieldPermission) pour créer des profils de sécurité de champ qui permettent aux applications d’envoyer des demandes de récupération d’enregistrements sans le masquage afin que les données puissent être affichées dans des circonstances contrôlées. En savoir plus sur la récupération des données non masquées
Créer une règle de masquage sécurisée
Chaque colonne qui affiche des données masquées doit faire référence à une ligne de table Règle de masquage sécurisée (MaskingRule). Vous pouvez créer des règles de masquage sécurisées dans Power Apps et les ajouter à votre solution, ou vous pouvez utiliser l’une des règles existantes.
Créez des enregistrements de table Colonne de Masquage Sécurisée (AttributeMaskingRule) pour spécifier une règle de masquage à utiliser par une colonne sécurisée.
Le diagramme suivant décrit ces tables :
Colonnes des règles de masquage sécurisées
La table Règle de masquage sécurisée (MaskingRule) contient les colonnes accessibles en écriture suivantes :
| Colonne | Type | Description |
|---|---|---|
Name |
chaîne | Nom unique de la règle de masquage sécurisée. |
Description |
chaîne | Description de la règle de masquage sécurisée. |
DisplayName |
chaîne | Nom d’affichage de la règle de masque sécurisé. |
MaskedCharacter |
chaîne | Caractère utilisé pour masquer. |
RegularExpression |
chaîne | Expression régulière dans C#. |
IsCustomizable |
Propriété boolean gérée | Information indiquant si ce composant est personnalisable. En savoir plus sur les propriétés gérées |
RichTestData |
chaîne | Définissez les données de test de texte enrichi pour tester cette règle de masquage sécurisée. |
MaskedRichTestData |
chaîne | Données de la colonne RichTestData évaluées par cette règle de masquage sécurisée. |
TestData |
chaîne | Définissez les données de test pour tester cette règle de masquage sécurisée. |
MaskedTestData |
chaîne | Données de la colonne TestData évaluées par une règle de masquage sécurisée. |
Note
Les colonnes RichTestData, MaskedRichTestData, TestData, et MaskedTestData existent pour prendre en charge l’expérience de test des règles de masquage dans Power Apps.
En savoir plus sur la création des règles de masquage.
Colonnes de masquage sécurisées
La table Secured Masking Column (AttributeMaskingRule) contient ces colonnes modifiables :
| Colonne | Type | Description |
|---|---|---|
AttributeLogicalName |
chaîne | Nom logique de la colonne pour laquelle la règle de masquage sécurisé est utilisée. |
EntityName |
chaîne | Nom logique de la table contenant la colonne. |
MaskingRuleId |
Recherche | La règle de masquage utilisée par la colonne |
UniqueName |
chaîne | Le nom unique de la colonne de masquage sécurisée. |
IsCustomizable |
BooleanManagedProperty | Information indiquant si ce composant est personnalisable. En savoir plus sur les propriétés gérées |
Récupérer les données non masquées
Lorsqu’une colonne de l’enregistrement Field Permission (FieldPermission) est autorisée, vous pouvez définir la CanReadUnmasked colonne de choix si la colonne a un enregistrement de colonne de masquage sécurisé (AttributeMaskingRule) associé.
La colonne CanReadUnmasked prend en charge les options suivantes définies par le choix global field_security_permission_readunmasked.
| Valeur | Étiquette | Description |
|---|---|---|
| 0 | Pas autorisé | Valeur par défaut. S’il n’y a pas AttributeMaskingRule de colonne, vous ne pouvez pas définir d’autre valeur. |
| 1 | Un enregistrement | Les données non masquées peuvent être retournées uniquement à l’aide d’une Retrieve opération. |
| 3 | Tous les enregistrements | Les données non masquées peuvent être retournées à l’aide de Retrieve et RetrieveMultiple des opérations. |
Exemple : récupérer les données non masquées
Les exemples suivants montrent comment utiliser le UnMaskedData paramètre facultatif pour demander que la valeur non masquée soit renvoyée lorsque la configuration de l’autorisation de champ le permet.
L’exemple GetUnmaskedExampleRows renvoie des valeurs non masquées pour toute des colonnes demandées où la valeur de la colonne CanReadUnmasked d’autorisation de champ est définie sur Tous les enregistrements, car le paramètre facultatif UnMaskedData est ajouté à la demande RetrieveMultiple.
Cette méthode interroge la table sample_example et récupère des colonnes spécifiques, y compris des données sensibles telles que l’ID officiel et la date de naissance. Les résultats de la requête sont classés par la colonne sample_name dans l’ordre décroissant.
/// <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;
}
Articles associés
Sécurité et accès aux données
Partage et attribution
Exemple : Sécurité au niveau de la colonne à l’aide de Dataverse SDK for .NET
Exemple : Sécurité au niveau de la colonne à l’aide de l’API web Dataverse (PowerShell)