本文介绍如何在 Microsoft Dataverse 中表的级联配置更改时删除记录的继承访问权限。
现象
将表关系的级联行为更改为无级联后,无论是针对Reparent操作还是Share操作,您仍然可以访问应该删除的相关记录。
如何验证对相关记录的访问权限
用户可能会报告他们获得了意外的记录访问权限。 可通过两种方式验证对相关记录的访问:使用 “检查访问 ”功能或 RetrieveAccessOrigin 消息。
使用“检查访问”功能
使用模型驱动应用中的 “检查访问 ”功能来检查谁有权访问记录。 管理员可以使用此功能来检查有权访问记录的单个用户或所有用户。
使用访问检查器时,会看到用户具有访问权限的原因列表。 其中一些原因显示是因获得了相关记录的访问权限而授予了共享。 例如:
- 记录与我共享,因为我有权访问相关记录。
- 因为团队能够访问相关记录,所以我所在的团队接收了共享记录。
使用 RetrieveAccessOrigin 消息
开发人员可以使用 RetrieveAccessOrigin 消息来检测哪些用户有权访问记录。 此消息返回一个句子,描述用户为何有权访问。 以下任何结果都表示由于共享相关记录而授予了访问权限:
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>)
有关详细信息,请参阅 “确定用户为何有权使用代码访问”。
原因
表关系级联行为发生更改时,Dataverse 会启动异步作业以删除以前授予的访问权限用户。 但是,此作业可能会失败,导致用户保留访问权限。
解决方法
解决此问题的第一步是重新创建系统作业以删除访问权限。 如果作业失败,开发人员可以使用 ResetInheritedAccess 消息将更改应用到指定的记录集。
重新创建系统作业以删除访问权限
开发人员可以使用 CreateAsyncJobToRevokeInheritedAccess 消息再次尝试创建异步作业。
使用 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);
}
详细了解如何将消息与 SDK for .NET 配合使用。
该操作将创建名为 CreateAsyncJobToRevokeInheritedAccessRevokeInheritedAccess 的新异步作业。 可以监视此作业的成功,但没有任何方法可以预览将受到影响的记录。 有关详细信息,请参阅 监视系统作业 或 使用代码管理系统作业。
重置继承的访问权限
如果 重新创建系统作业以删除访问权限 失败,则具有系统管理员或系统定制器权限的开发人员可以使用 ResetInheritedAccess 该消息以匹配记录的子集为目标。 可能需要多次使用此消息来删除对所有记录的访问权限。
/// <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"]);
}
详细了解如何将消息与 SDK for .NET 配合使用。
当匹配的记录不多时,ResetInheritedAccess 消息会尝试同步执行。 然后 ResetInheritedAccessResponse 值以 ExecutionMode : Sync 结尾。 如果有许多匹配记录,则操作需要更长的时间,并且值以结尾 ExecutionMode : Async。 已创建名为 Denormalization_PrincipalObjectAccess_principalobjectaccess:<caller ID> 的系统作业,可以监视该作业的成功。 有关详细信息,请参阅 监视系统作业 或 使用代码管理系统作业。
该 ResetInheritedAccess 消息需要 FetchXml 查询来标识记录。 此查询必须满足以下要求:
- 使用principalobjectaccess(POA)表。
- 仅返回 principalobjectaccessid列。
- 不得包含任何 link-entity元素。 不能将联接添加到另一个表。
- 仅对 principalobjectaccess表的列进行筛选。
此表作为principalobjectaccess 实体类型可供 Web API 使用。 它不包括在 Dataverse 表/实体引用 中,因为 POA 表不支持任何类型的直接数据修改操作。 需要知道此表的列以组成 FetchXml 查询。
POA 表列
只需使用这些列编写 FetchXml 查询。
| 逻辑名称 | 类型 | 说明 | 
|---|---|---|
| accessrightsmask | 整数 | 包含主体直接拥有的访问权限组合的 AccessRights 枚举 成员值。 | 
| changedon | 日期时间 | 主体访问记录的最后一个日期已更改。 | 
| inheritedaccessrightsmask | 整数 | 包含由于继承而应用的访问权限的组合 AccessRights 枚举 成员值。 | 
| objectid | 唯一标识符 | 主体有权访问的记录的 ID。 | 
| objecttypecode | 整数 | 对应于 表的 EntityMetadata.ObjectTypeCode 值。 对于不同的环境,此值不一定相同。 对于自定义表,会根据创建表的顺序分配该表。 若要获取此值,可能需要查看表的元数据。 有几个社区工具可以找到这一点。 这是来自 Microsoft 的解决方案:浏览您环境中的表定义。 | 
| principalid | 唯一标识符 | 有权访问的用户或团队的 ID。 | 
| principalobjectaccessid | 唯一标识符 | POA 表的主键。 | 
| principaltypecode | 整数 | 主体的类型代码。 SystemUser= 8,Team= 9。 | 
以下 AccessRights 枚举 成员值适用于 accessrightsmask 列和 inheritedaccessrightsmask 列:
| 访问类型 | 值 | 说明 | 
|---|---|---|
| None | 0 | 无访问权限。 | 
| Read | 1 | 读取记录的权利。 | 
| Write | 2 | 更新记录的权利。 | 
| Append | 4 | 将指定记录附加到另一条记录。 | 
| AppendTo | 16 | 添加将另一条记录追加到指定记录上的权限。 | 
| Create | 32 | 创建记录的权利。 | 
| Delete | 65,536 | 删除记录的权利。 | 
| Share | 262,144 | 共享记录的权利。 | 
| Assign | 524,288 | 向其他用户或团队分配指定记录的权利。 | 
你可能会发现该值 inheritedaccessrightsmask 通常为 135,069,719。 此值包括除上述所有访问类型之外 Create的所有访问类型,这并非必要,因为这些权限仅适用于已创建的记录。
FetchXml 示例
本部分包括一些可用于 ResetInheritedAccess 消息的 FetchXml 查询示例。 有关详细信息,请参阅 使用 FetchXML 构造查询。
重置授予给特定用户的特定帐户的继承访问权限
<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>
为指定对象类型的所有子行重置给定的继承访问权限
<fetch>
    <entity name="principalobjectaccess">
        <attribute name="principalobjectaccessid"/>
        <filter type="and">
            <condition attribute="objecttypecode" operator="eq" value="10042" />
        </filter>
    </entity>
</fetch>
重置针对所有对象类型的指定用户授予的继承访问权限
<fetch>
    <entity name="principalobjectaccess">
        <attribute name="principalobjectaccessid"/>
        <filter type="and">
            <condition attribute="principalid" operator="eq" value="9b5f621b-584e-423f-99fd-4620bb00bf1f" />
        </filter>
    </entity>
</fetch>