Guide pratique pour propre l’accès hérité

Cet article explique comment supprimer l’accès hérité aux enregistrements lorsque la configuration en cascade d’une table change dans Microsoft Dataverse.

Symptômes

Une fois que le comportement en cascade d’une relation de table pour l’action Réparent ou Partager est remplacé par Aucune cascade, vous continuez à avoir accès aux enregistrements associés qui doivent être supprimés.

Les utilisateurs peuvent signaler qu’ils disposent d’un accès inattendu aux enregistrements. Il existe deux façons de vérifier l’accès aux enregistrements associés : à l’aide de la fonctionnalité Vérifier l’accès ou du RetrieveAccessOrigin message.

Utiliser la fonctionnalité Vérifier l’accès

Utilisez la fonctionnalité Vérifier l’accès dans les applications pilotées par modèle pour case activée qui a accès à un enregistrement. Les administrateurs peuvent utiliser cette fonctionnalité pour case activée utilisateurs individuels ou tous les utilisateurs qui ont accès à un enregistrement.

Lorsque vous utilisez le vérificateur d’accès, vous voyez une liste des raisons pour lesquelles un utilisateur a accès. Certaines de ces raisons indiquent que le partage a été accordé en raison de l’accès à un enregistrement associé. Par exemple :

  • L’enregistrement a été partagé avec moi, car j’ai accès à l’enregistrement associé.
  • L’enregistrement a été partagé avec les équipes dont je suis membre, car l’équipe a accès à l’enregistrement associé.

Utiliser le message RetrieveAccessOrigin

Les développeurs peuvent utiliser le RetrieveAccessOrigin message pour détecter les utilisateurs qui ont accès à un enregistrement. Ce message retourne une phrase décrivant pourquoi l’utilisateur a l’accès. L’un des résultats suivants indique que l’accès a été accordé en raison du partage d’un enregistrement associé :

PrincipalId is owner of a parent entity of object (<record ID>)
PrincipalId is member of team (<team ID>) who is owner of a parent entity of object (<record ID>)
PrincipalId is member of organization (<organization ID>) who is owner of a parent entity of object (<record ID>)
PrincipalId has access to (<parent record ID>) through hierarchy security. (<parent record ID>) is owner of a parent entity of object (<record ID>)

Pour plus d’informations, consultez Déterminer pourquoi un utilisateur a accès avec du code.

Cause

Lorsque le comportement en cascade d’une relation de table change, Dataverse démarre un travail asynchrone pour supprimer l’accès précédemment accordé aux utilisateurs. Toutefois, ce travail peut échouer, entraînant la conservation de l’accès par les utilisateurs.

Résolution

La première étape pour résoudre ce problème consiste à recréer le travail système pour supprimer l’accès. Si le travail échoue, un développeur peut utiliser le ResetInheritedAccess message pour appliquer la modification à un jeu d’enregistrements spécifié.

Recréer le travail système pour supprimer l’accès

Les développeurs peuvent utiliser le CreateAsyncJobToRevokeInheritedAccess message pour essayer de créer à nouveau un travail asynchrone.

Utilisez la classe Microsoft.Xrm.Sdk.Messages.CreateAsyncJobToRevokeInheritedAccessRequest.

/// <summary>
/// Creates and executes an asynchronous cleanup job to revoke inherited access granted through cascading inheritance.
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
/// <param name="relationshipSchemaName">The schema name of the entity relationship.</param>
public static void CreateAsyncJobToRevokeInheritedAccessExample(IOrganizationService service, string relationshipSchemaName)
{
    var request = new Microsoft.Xrm.Sdk.Messages.CreateAsyncJobToRevokeInheritedAccessRequest()
    {
        RelationshipSchema = relationshipSchemaName
    };

    service.Execute(request);
}

En savoir plus sur l’utilisation des messages avec le Kit de développement logiciel (SDK) pour .NET.

L’action CreateAsyncJobToRevokeInheritedAccess crée un travail asynchrone nommé RevokeInheritedAccess. Vous pouvez surveiller la réussite de ce travail. Pour plus d’informations, consultez Surveillance des travaux système ou Gestion des travaux système avec du code.

Réinitialiser l’accès hérité

Si la recréation du travail système pour supprimer l’accès échoue, un développeur disposant de privilèges d’administrateur système ou de personnalisateur système peut utiliser le ResetInheritedAccess message pour cibler un sous-ensemble d’enregistrements correspondants. Vous devrez peut-être utiliser ce message plusieurs fois pour supprimer l’accès à tous les enregistrements.

/// <summary>
/// Resets the inherited access for the matching records.
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
/// <param name="fetchXml">The fetchxml query.</param>
public static void OutputResetInheritedAccess(IOrganizationService service, string fetchXml)
{
    var parameters = new ParameterCollection()
    {
        { "FetchXml", fetchXml}
    };

    var request = new OrganizationRequest()
    {
        RequestName = "ResetInheritedAccess",
        Parameters = parameters
    };

    var response = service.Execute(request);

    Console.WriteLine(response.Results["ResetInheritedAccessResponse"]);
}

En savoir plus sur l’utilisation des messages avec le Kit de développement logiciel (SDK) pour .NET.

Le ResetInheritedAccess message tente de s’exécuter de façon synchrone lorsqu’il n’y a pas beaucoup d’enregistrements correspondants. Ensuite, la ResetInheritedAccessResponse valeur se termine par ExecutionMode : Sync. S’il existe de nombreux enregistrements correspondants, l’opération prend plus de temps et la valeur se termine par ExecutionMode : Async. Un travail système nommé Denormalization_PrincipalObjectAccess_principalobjectaccess:<caller ID> est créé et vous pouvez surveiller la réussite de ce travail. Pour plus d’informations, consultez Surveillance des travaux système ou Gestion des travaux système avec du code.

Le ResetInheritedAccess message nécessite une requête FetchXml pour identifier les enregistrements. Cette requête doit répondre aux exigences suivantes :

  • Utilisez la principalobjectaccesstable (POA).
  • Retourne uniquement la principalobjectaccessid colonne.
  • Ne doit pas inclure d’éléments link-entity . Vous ne pouvez pas ajouter une jointure à une autre table.
  • Filtrez uniquement sur les colonnes de la principalobjectaccess table.

Cette table est disponible pour l’API web en tant que type d’entité principalobjectaccess. Il n’est pas inclus dans la référence d’entité/table Dataverse , car la table POA ne prend en charge aucun type d’opération de modification directe des données. Vous devez connaître les colonnes de cette table pour composer la requête FetchXml.

Colonnes de table POA

Vous devez composer une requête FetchXml en utilisant uniquement ces colonnes.

Nom logique Type Description
accessrightsmask Entier Contient les valeurs de membre enum AccessRights combinées pour les droits d’accès dont dispose directement le principal.
changedon DateTime Date de la dernière modification de l’accès du principal à l’enregistrement.
inheritedaccessrightsmask Entier Contient les valeurs de membre d’énumération AccessRights combinées pour les droits d’accès appliqués en raison de l’héritage.
objectid Identificateur unique ID de l’enregistrement auquel le principal a accès.
objecttypecode Entier Valeur EntityMetadata.ObjectTypeCode qui correspond à la table. Cette valeur n’est pas nécessairement la même pour les différents environnements. Pour les tables personnalisées, elle est attribuée en fonction de l’ordre dans lequel la table a été créée. Pour obtenir cette valeur, vous devrez peut-être afficher les métadonnées de la table. Il existe plusieurs outils de la communauté pour trouver cela. Voici une solution de Microsoft : Parcourir les définitions de table dans votre environnement.
principalid Identificateur unique ID de l’utilisateur ou de l’équipe qui a accès.
principalobjectaccessid Identificateur unique Clé primaire de la table POA.
principaltypecode Entier Code de type du principal. SystemUser = 8, Team = 9.

Les valeurs de membre d’énumération AccessRights suivantes s’appliquent accessrightsmask aux colonnes et inheritedaccessrightsmask :

Type d’accès Valeur Description
None 0 Pas d’accès.
Read 1 Droit de lire un enregistrement.
Write 2 Droit de mettre à jour un enregistrement.
Append 4 Droit d’ajouter l’enregistrement spécifié à un autre enregistrement.
AppendTo 16 Droit d’ajouter un autre enregistrement à l’enregistrement spécifié.
Create 32 Droit de créer un enregistrement.
Delete 65,536 Droit de supprimer un enregistrement.
Share 262,144 Droit de partager un enregistrement.
Assign 524,288 Droit d’attribuer l’enregistrement spécifié à un autre utilisateur ou équipe.

Vous pouvez voir que la inheritedaccessrightsmask valeur est généralement 135 069 719. Cette valeur inclut tous les types d’accès à l’exception de Create, ce qui n’est pas nécessaire, car ces droits s’appliquent uniquement aux enregistrements déjà créés.

Exemples FetchXml

Cette section inclut quelques exemples de requêtes FetchXml que vous pouvez utiliser avec le ResetInheritedAccess message. Pour plus d’informations, consultez Utiliser FetchXML pour construire une requête.

Réinitialiser l’accès hérité accordé à un certain utilisateur pour un compte spécifique
<fetch>
    <entity name="principalobjectaccess">
        <attribute name="principalobjectaccessid"/>
        <filter type="and">
            <condition attribute="principalid" operator="eq" value="9b5f621b-584e-423f-99fd-4620bb00bf1f" />
            <condition attribute="objectid" operator="eq" value="B52B7A48-EAFB-ED11-884B-00224809B6C7" />
        </filter>
    </entity>
</fetch>
Réinitialiser l’accès hérité accordé à toutes les lignes enfants pour un type d’objet spécifié
<fetch>
    <entity name="principalobjectaccess">
        <attribute name="principalobjectaccessid"/>
        <filter type="and">
            <condition attribute="objecttypecode" operator="eq" value="10042" />
        </filter>
    </entity>
</fetch>
Réinitialiser l’accès hérité accordé à un utilisateur spécifié pour tous les types d’objets
<fetch>
    <entity name="principalobjectaccess">
        <attribute name="principalobjectaccessid"/>
        <filter type="and">
            <condition attribute="principalid" operator="eq" value="9b5f621b-584e-423f-99fd-4620bb00bf1f" />
        </filter>
    </entity>
</fetch>