我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面的微软最有价值专家(Microsoft MVP),欢迎关注我的微信公众号 MSFTDynamics365erLuoYong ,回复385或者20191218可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!

我前面的博文 探索Dynamics 365 用户能够登录使用的最小权限需求 讲述了需要登录系统的最小权限,我们再来配置一个角色让拥有这个角色的用户可以更改用户的业务部门及角色。

在这之前我已经将 Common Data Service minimum privilege security role 解决方案导入了我的Dynamics 365中,导入后会有一个名称为 min priv apps use 的角色。

首先我们用系统管理员账号来克隆出来一个角色,打开 min priv apps use 这个角色,点击【Actions】 > 【Copy Role】按钮。

输入角色名称,然后点击【OK】按钮就会复制成功,默认情况下会打开该角色。

值得一提的是,如果用户更改所属业务部门,就会丢失其原有的所有角色,所以首先考虑是否要更换用户所属业务部门,若要,首先更改改用户所属的业务部门,记录下其原有的角色。

经过一番测试,我找到了需要能够更改用户的业务部门和角色需要的增加的权限如下:

  • Service Management Tab的Calendar实体的全部权限
  • Business Management Tab的User实体的写权限,全局级别,因为用户进入后默认挂在根业务部门上,操作更改的用户很可能已经不挂在根业务部门上了,要能更改用户信息需要全局写权限
  • Business Management Tab 的Security Role的分派权限,全局级别
  • Business Management Tab 的User Settings实体的写权限,全局级别
  • Customization Tab 的Activate Real-time Processes权限,全局级别,此权限为杂项权限
  • Customization Tab 的System Job实体的追加到权限,全局级别
  • Customization Tab 的System Job实体的分派权限,全局级别
  • Customization Tab 的System Job实体的读权限,全局级别
  • Customization Tab 的System Job实体的写权限,全局级别
  • Customization Tab 的Process Session实体的追加到权限,全局级别
  • Customization Tab 的Process Session实体的追加权限,全局级别
  • Customization Tab 的Process Session实体的分派权限,全局级别
  • Customization Tab 的Process Session实体的创建权限,全局级别
  • Customization Tab 的Process Session实体的删除权限,全局级别
  • Customization Tab 的Process Session实体的共享权限,全局级别
  • Customization Tab 的Process Session实体的写权限,全局级别
  • Customization Tab 的Process实体的追加权限,全局级别
  • Customization Tab 的Process实体的分派权限,全局级别
  • Customization Tab 的Process实体的创建权限,全局级别
  • Customization Tab 的Process实体的删除权限,全局级别
  • Customization Tab 的Process实体的共享权限,全局级别
  • Customization Tab 的Process实体的写权限,全局级别
  • Core Records Tab 的Report实体的读取权限,全局级别
  • Reparent User,这个是杂项权限,拥有这个权限才能看到【Change Business Unit】按钮,权限级别根据需要而定,比如你如果需要授予用户的角色只能是本业务部门的角色,那么设置为业务部门级别,如果包括下级业务部门的角色,则设置为上:下级业务部门级别,任何业务部门的角色的话,则授予全局级别。

截图说明如下:

如果还需要显示用户表单的【REASSIGN RECORDS】的话,需要授予【Enable or Disable User】权限。

如果要求更改业务部门,除了系统管理员操作外,只能更改为操作者一样的业务部门的话,我这里使用插件来验证,我写了一个名称为PreSystemUserUpdate.cs的类,代码如下:

  1. using Microsoft.Xrm.Sdk;
  2. using Microsoft.Xrm.Sdk.Query;
  3. using System;
  4.  
  5. namespace PluginDemo
  6. {
  7. public class PreSystemUserUpdate : IPlugin
  8. {
  9. public void Execute(IServiceProvider serviceProvider)
  10. {
  11. //获取日志服务
  12. ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
  13. //写一些日志,方便跟踪
  14. tracingService.Trace($"Enter PreSystemUserUpdate on {DateTime.UtcNow.ToString()}");
  15. IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
  16. if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
  17. {
  18. //插件针对的当前实体记录,对于Pre Update消息来讲,该对象包括了所有设置的字段值,若字段没有设置值,在该对象中会不存在
  19. Entity currentEntity = (Entity)context.InputParameters["Target"];
  20. //获取组织服务
  21. IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
  22. IOrganizationService orgSvc = serviceFactory.CreateOrganizationService(context.UserId);
  23. //如果更新的字段包括Business Unit
  24. if (currentEntity.Contains("businessunitid"))
  25. {
  26. tracingService.Trace($"Current user will change Business Unit on {DateTime.UtcNow.ToString()}");
  27. //检查当前用户是否具有System Administrator角色
  28. string fetchXml = string.Format(@"<fetch version='1.0' mapping='logical' distinct='false' no-lock='true' top='1'>
  29. <entity name='systemuser'>
  30. <attribute name='systemuserid' />
  31. <attribute name='businessunitid' />
  32. <filter type='and'>
  33. <condition attribute='systemuserid' operator='eq' value='{0}' />
  34. </filter>
  35. <link-entity name='systemuserroles' from='systemuserid' to='systemuserid' visible='false' intersect='true'>
  36. <link-entity name='role' from='roleid' to='roleid' alias='ac'>
  37. <filter type='and'>
  38. <condition attribute='name' operator='eq' value='System Administrator' />
  39. </filter>
  40. </link-entity>
  41. </link-entity>
  42. </entity>
  43. </fetch>", context.UserId);
  44. //不具有System Administrator角色的用户更改用户的业务部门时候,只能更改为与当前用户相同的业务部门
  45. if (orgSvc.RetrieveMultiple(new FetchExpression(fetchXml)).Entities.Count == )
  46. {
  47. var currentUserBU = orgSvc.Retrieve("systemuser", context.UserId, new ColumnSet("businessunitid")).GetAttributeValue<EntityReference>("businessunitid");
  48. tracingService.Trace($"Current user's business unit name is {currentUserBU.Name}");
  49. if (currentEntity.GetAttributeValue<EntityReference>("businessunitid").Id != currentUserBU.Id)
  50. {
  51. throw new InvalidPluginExecutionException($"你只能更改当前用户的业务部门为你所在的业务部门-{currentUserBU.Name}");
  52. }
  53. }
  54. }
  55. }
  56. tracingService.Trace($"Leave PreSystemUserUpdate on {DateTime.UtcNow.ToString()}");
  57. }
  58. }
  59. }

然后还是注册插件,大部分步骤可以参考我前面的博文 Dynamics 365中开发和注册插件介绍 ,还是先注册程序集,如下图:

然后右击插件类注册新步骤,如下图:

设置如下图,可以看到是注册到SystemUser实体的Update消息的Pre Operation阶段,注意要筛选字段,我这里筛选字段为 businessunitid,很多人注册Update消息上的插件不筛选字段,那么触发会非常频繁,这是不好的做法。

注册后去测试,如果报错,效果如下:

如果你能授予他人的的角色权限包括了你没有的权限,那就是安全漏洞了。如果你要授予他人的的角色权限包括了你没有的权限系统会报错,下面是一个报错的截图。

至于权限名称,比如prvActivateBusinessProcessFlow 对应界面上的那个项目,可以通过 Security role UI to privilege mapping 来查询。

如果是限定只能更改到哪些业务部门,可以参考下面代码:

  1. using Microsoft.Xrm.Sdk;
  2. using Microsoft.Xrm.Sdk.Query;
  3. using System;
  4.  
  5. namespace PluginDemo
  6. {
  7. public class PreSystemUserUpdate : IPlugin
  8. {
  9. public void Execute(IServiceProvider serviceProvider)
  10. {
  11. //获取日志服务
  12. ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
  13. //写一些日志,方便跟踪
  14. tracingService.Trace($"Enter PreSystemUserUpdate on {DateTime.UtcNow.ToString()}");
  15. IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
  16. if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
  17. {
  18. //插件针对的当前实体记录,对于Pre Update消息来讲,该对象包括了所有设置的字段值,若字段没有设置值,在该对象中会不存在
  19. Entity currentEntity = (Entity)context.InputParameters["Target"];
  20. Entity preImgEntity;
  21. //获取组织服务
  22. IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
  23. IOrganizationService orgSvc = serviceFactory.CreateOrganizationService(context.UserId);
  24. //如果更新的字段包括Business Unit
  25. if (currentEntity.Contains("businessunitid"))
  26. {
  27. tracingService.Trace($"Current user will change Business Unit on {DateTime.UtcNow.ToString()}");
  28. //检查当前用户是否具有System Administrator角色
  29. string fetchXml = string.Format(@"<fetch version='1.0' mapping='logical' distinct='true' no-lock='true' top='1'>
  30. <entity name='systemuser'>
  31. <attribute name='systemuserid' />
  32. <attribute name='businessunitid' />
  33. <filter type='and'>
  34. <condition attribute='systemuserid' operator='eq' value='{0}' />
  35. </filter>
  36. <link-entity name='systemuserroles' from='systemuserid' to='systemuserid' visible='false' intersect='true'>
  37. <link-entity name='role' from='roleid' to='roleid' alias='ac'>
  38. <filter type='and'>
  39. <condition attribute='name' operator='eq' value='System Administrator' />
  40. </filter>
  41. </link-entity>
  42. </link-entity>
  43. </entity>
  44. </fetch>", context.UserId);
  45. //不具有System Administrator角色的用户更改用户的业务部门时候,只能更改为与当前用户相同的业务部门
  46. if (orgSvc.RetrieveMultiple(new FetchExpression(fetchXml)).Entities.Count == )
  47. {
  48. tracingService.Trace($"Current user does not have system administrator role {DateTime.UtcNow.ToString()}");
  49. if (context.PreEntityImages.Contains("PreImg"))
  50. {
  51. preImgEntity = context.PreEntityImages["PreImg"];
  52. }
  53. else
  54. {
  55. throw new InvalidPluginExecutionException("Pre Update image - PreImg does not exist!");
  56. }
  57. var userOrigBU = preImgEntity.GetAttributeValue<EntityReference>("businessunitid");
  58. var currentUserBU = orgSvc.Retrieve("systemuser", context.UserId, new ColumnSet("businessunitid")).GetAttributeValue<EntityReference>("businessunitid");
  59. tracingService.Trace($"Current user's business unit name is {currentUserBU.Name}");
  60. //找到出根业务部门
  61. var buRootQE = new QueryExpression("businessunit");
  62. buRootQE.NoLock = true;
  63. buRootQE.TopCount = ;
  64. buRootQE.ColumnSet = new ColumnSet("businessunitid");
  65. buRootQE.Criteria.AddCondition("parentbusinessunitid", ConditionOperator.Null);
  66. var buRootId = orgSvc.RetrieveMultiple(buRootQE).Entities[].Id;
  67. tracingService.Trace($"Root BU id= {buRootId.ToString()} {DateTime.UtcNow.ToString()}");
  68. var canChange = false;
  69. Guid parentBUId = Guid.Empty;
  70. Entity buEntity;
  71. var newBUId = currentEntity.GetAttributeValue<EntityReference>("businessunitid").Id;
  72. if (userOrigBU.Id == buRootId)//如果用户的原部门是根业务部门
  73. {
  74. //只能将用户改到操作者所在的业务部门及其下级业务部门
  75. if(newBUId == currentUserBU.Id)
  76. {
  77. canChange = true;
  78. }
  79. else
  80. {
  81. buEntity = orgSvc.Retrieve("businessunit", newBUId, new ColumnSet("parentbusinessunitid"));
  82. while (buEntity.Contains("parentbusinessunitid"))
  83. {
  84. parentBUId = buEntity.GetAttributeValue<EntityReference>("parentbusinessunitid").Id;
  85. if (parentBUId == currentUserBU.Id)
  86. {
  87. canChange = true;
  88. break;
  89. }
  90. buEntity = orgSvc.Retrieve("businessunit", parentBUId, new ColumnSet("parentbusinessunitid"));
  91. }
  92. }
  93. }
  94. else
  95. {
  96. //只允许将本部门或者下级部门用户的业务部门改到根业务部门
  97. if(newBUId == buRootId)
  98. {
  99. if(userOrigBU.Id == currentUserBU.Id)
  100. {
  101. canChange = true;
  102. }
  103. else
  104. {
  105. buEntity = orgSvc.Retrieve("businessunit", userOrigBU.Id, new ColumnSet("parentbusinessunitid"));
  106. while (buEntity.Contains("parentbusinessunitid"))
  107. {
  108. parentBUId = buEntity.GetAttributeValue<EntityReference>("parentbusinessunitid").Id;
  109. if (parentBUId == currentUserBU.Id)
  110. {
  111. canChange = true;
  112. break;
  113. }
  114. buEntity = orgSvc.Retrieve("businessunit", parentBUId, new ColumnSet("parentbusinessunitid"));
  115. }
  116. }
  117. }
  118. }
  119. if (!canChange)
  120. {
  121. throw new InvalidPluginExecutionException($"更改业务部门不合规!");
  122. }
  123. }
  124. }
  125. }
  126. tracingService.Trace($"Leave PreSystemUserUpdate on {DateTime.UtcNow.ToString()}");
  127. }
  128. }
  129. }

注意这个代码需要添加一个Pre阶段的Image,请参考下图注册:

注册好Image后的截图如下:

如果是更新插件代码的话,选择对应得程序集,右击,选择【Update】进行更新。

Dynamics 365需要的最小的权限用来更改用户的业务部门和角色的更多相关文章

  1. Dynamics 365中的分派(Assign)。

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  2. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(四)基于Shiro验证用户权限,且给用户授权

    最新项目比较忙,写文章的精力就相对减少了,但看到邮箱里的几个催更,还是厚颜把剩下的文档补上. 一.修改ShiroDbRealm类,实现它的doGetAuthorizationInfo方法 packag ...

  3. 探索Dynamics 365 用户能够登录使用的最小权限需求

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  4. 为实施了IFD的Dynamics 365更换自签名的SSL证书以符合Chrome的要求

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复259或者20170704可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  5. Dynamics 365中部分账号使用系统明显缓慢怎么办?先这么干!

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复263或者20170828可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  6. 如何让用户登录Dynamics 365 Customer Engagement后自动登录到Unified Interface App?

    微软动态CRM专家罗勇 ,回复324或者20190422可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! Dynamics 365 Customer Engagement ...

  7. Dynamics 365 Customer Engagement中插件的调试

    微软动态CRM专家罗勇 ,回复319或者20190319可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 本文主要根据官方的教 ...

  8. Dynamics 365 启用跟踪及读取跟踪文件工具

    微软动态CRM专家罗勇 ,回复315或者20190313可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 当根据错误提示排查问 ...

  9. Dynamics 365 POA表记录的产生

    微软动态CRM专家罗勇 ,回复314或者20190311可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 前面的博文 Dyna ...

随机推荐

  1. 学习之Redis(一)

    一.redis简介 一般学习,最好先去官网,之所以建议看官网,是因为这是一手的学习资料,其他资料都最多只能算二手,一手资料意味着最权威,准确性最高.https://redis.io/topics/in ...

  2. linux 安装jmeter

    一 下载jdk sudo apt install oracle-java8-installer 二 网站下载 jmeter 三 对jmeter文件夹 赋权 我都是777 chmod -R 777 ap ...

  3. Postman 关联接口测试(带有token鉴权)

    Postman 关联接口测试(带有token鉴权) 一.登陆接口 创建一个request请求 在Tests中添加JavaScript代码,用来获取鉴权 pm.test("V2", ...

  4. Windows安装MSYS2_切换zsh_整合cmder

    MSYS2是什么 MSYS2 (Minimal SYStem 2) 是一个MSYS的独立改写版本,主要用于 shell 命令行开发环境.同时它也是一个在Cygwin (POSIX 兼容性层) 和 Mi ...

  5. 小白的springboot之路(十)、全局异常处理

    0.前言 任何系统,我们不会傻傻的在每一个地方进行异常捕获和处理,整个系统一般我们会在一个的地方统一进行异常处理,spring boot全局异常处理很简单: 介绍前先说点题外话,我们现在开发系统,都是 ...

  6. Linux常见指令大全

    转载自https://www.cnblogs.com/caozy/p/9261224.html 前言 本文特点 授之以渔:了解命令学习方法.用途:不再死记硬背,拒绝漫无目的: 准确无误:所有命令执行通 ...

  7. NodeJS3-1基础API----Path(路径)

    path 和路径有关的操作 Path(路径)  path 模块提供用于处理文件路径和目录路径的实用工具. 它可以使用以下方式访问 const path = require('path');  1. p ...

  8. Django项目BBS博客论坛

    BBS 项目开发逻辑梳理 第一步:先进行数据库设计 数据库设计规则是: 1.先创建基表:用户表.站点表.文章表.标签表.分类表.文章2标签第三张关系表.点赞点踩表.评论表 2.书写表中的基本含有的字段 ...

  9. Django之视图层与模板层

    目录 视图层 小白必会三板斧 HttpResponse render redirect JsonResponse 前后端分离 FBV CBV 给CBV加装饰器 模板层 模板语法 模板传值 过滤器 语法 ...

  10. Python是什么?你真的了解Python吗?

    一.Python是什么相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是一种开发语言,而且已经进阶到 ...