You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
7.7 KiB

  1. <?php
  2. namespace backend\logic;
  3. use ReflectionClass;
  4. use ReflectionException;
  5. use yii;
  6. class PermissionManager
  7. {
  8. /**
  9. * 获取app的已做标记控制器的权限
  10. * DESCRIBE 控制器描述,只有控制器的注释添加了该描述,才会自动匹配该控制器;使用例子:DESCRIBE {controllerDescribe} DESCRIBE
  11. * ACTION 方法描述,只有控制器下action方法的注释添加了该描述,才会自动匹配该action方法;使用例子:ACTION {actionDescribe} ACTION
  12. * 匹配控制器中actions的方法,需要添加id参数并且在标明含义,例子:
  13. * '{actionName}' => [
  14. * 'class' => 'xxx\xxx\xxx',
  15. * 'id' => '{actionDescribe}'
  16. * ]
  17. * @return array 返回已匹配到的权限。返回例子:[["{controllerDescribe}"=>["{actionDescribe}"=>"action route"]]]
  18. * @throws yii\base\InvalidConfigException
  19. * @throws ReflectionException
  20. */
  21. public static function getAppPermission()
  22. {
  23. $permission = [];
  24. $permission = self::getControllersAndActions($permission); //获取该app的所有controller权限
  25. $permission = self::getModuleControllerAndAction($permission); //获取该app引用module的所有controller权限
  26. return $permission;
  27. }
  28. /**
  29. * 获取app下controller已标记的action方法权限
  30. * 这个方法先是获取该app下controller的路径,控制器的命名空间,然后匹配该路径下面的所有控制器文件
  31. * 截取控制器文件的控制器基础名称,转换为相应url规则名称,拼接为相应类名
  32. * 根据控制器id,通过[[Module::createControllerByID]]方法实例化该控制器,最后通过[[PermissionManager::constructingPermissionArray]]获取所有已标记的权限
  33. * @param array $permission 权限数组
  34. * @return array 权限数组
  35. * @throws yii\base\InvalidConfigException
  36. * @throws ReflectionException
  37. */
  38. private static function getControllersAndActions($permission = [])
  39. {
  40. $dir = Yii::$app->getControllerPath();
  41. $nameSpace = Yii::$app->controllerNamespace . "\\";
  42. $fileList = glob($dir."/*Controller.php");
  43. foreach ($fileList as $file) {
  44. $baseName = substr(basename($file), 0, -14);
  45. //根据路由规则转换控制器名称
  46. $name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName));
  47. $id = ltrim(str_replace(' ', '-', $name), '-');
  48. $className = $nameSpace . $baseName . 'Controller';
  49. $controller = Yii::$app->createControllerByID($id);
  50. $permission = self::constructingPermissionArray($controller, $className, $permission);
  51. }
  52. return $permission;
  53. }
  54. /**
  55. * 获取该app下关联module的已标记controller的权限
  56. * 这个方法通过[[Module::getModules]]获取该app下关联的module并循环
  57. * 去除gii和debug,通过[[Module::getModule]]获取子类module,获取命名空间,文件位置,然后匹配该路径下面的所有控制器文件
  58. * 截取控制器文件的控制器基础名称,转换为相应url规则名称,拼接为相应类名
  59. * 通过[[BaseYii::createObject]]实例化,最后通过[[PermissionManager::constructingPermissionArray]]获取所有已标记的权限
  60. * @param array $permission 权限数组
  61. * @return array 权限数组
  62. * @throws yii\base\InvalidConfigException
  63. * @throws ReflectionException
  64. */
  65. private static function getModuleControllerAndAction($permission = [])
  66. {
  67. foreach (Yii::$app->getModules() as $id => $child) {
  68. if(in_array($id, ['gii', 'debug'])) {
  69. continue;
  70. }
  71. $module = Yii::$app->getModule($id);
  72. $nameSpace = $module->controllerNamespace."\\";
  73. $dir = $module->controllerPath;
  74. $fileList = glob($dir."/*Controller.php");
  75. foreach ($fileList as $file) {
  76. $baseName = substr(basename($file), 0, -14);
  77. $name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName));
  78. $id = $module->id.'/'.ltrim(str_replace(' ', '-', $name), '-');
  79. $className = $nameSpace . $baseName . 'Controller';
  80. $controller = Yii::createObject($className, [$id, $module]);
  81. $permission = self::constructingPermissionArray($controller, $className, $permission);
  82. }
  83. }
  84. return $permission;
  85. }
  86. /**
  87. * 构建权限数组
  88. * 根据类名,使用ReflectionClass方法获取该类的信息
  89. * 通过该类的注释,判断是否存在DESCRIBE标记,以此判断是否要记录该类的权限
  90. * 若存在标记,则通过[[PermissionManager::getActionsInController]]获取actions里面的方法权限数组,通过[[PermissionManager::getActionInController]]获取该类下面的action方法权限数组
  91. * @param $controllerObject
  92. * @param $className
  93. * @param array $permission 权限数组
  94. * @return array 权限数组
  95. * @throws ReflectionException
  96. */
  97. private static function constructingPermissionArray($controllerObject, $className, $permission = [])
  98. {
  99. $prefix = '/'.$controllerObject->id.'/';
  100. $reflection = new ReflectionClass($className); //通过ReflectionClass方法获取该类的所有信息,包括参数方法等
  101. $controllerComment = $reflection->getDocComment();
  102. $controllerPregRes = preg_match("/(?<=DESCRIBE ).*?(?= DESCRIBE)/", $controllerComment, $controllerDescribe);
  103. if ($controllerPregRes) {
  104. $permission = self::getActionsInController($controllerObject, $controllerDescribe, $prefix, $permission);
  105. $permission = self::getActionInController($reflection, $prefix, $controllerDescribe, $permission);
  106. }
  107. return $permission;
  108. }
  109. /**
  110. * 获取控制器类中actions的方法权限
  111. * 根据实例化的控制器类,获取actions的方法并且循环,方法存在id这个参数,则记录
  112. * 最后放回权限数组
  113. * @param $controllerObject
  114. * @param $controllerDescribe
  115. * @param $prefix
  116. * @param array $permission 权限数组
  117. * @return array 权限数组
  118. */
  119. private static function getActionsInController($controllerObject, $controllerDescribe, $prefix, $permission = [])
  120. {
  121. foreach ($controllerObject->actions() as $id => $item) {
  122. if (isset($item['id'])) {
  123. $permission[$controllerDescribe[0]][$item['id']] = $prefix . $id;
  124. }
  125. }
  126. return $permission;
  127. }
  128. /**
  129. * 获取控制器类中的action方法权限
  130. * 获取所有的action方法,若注释中存在ACTION标记,则记录
  131. * @param $controllerObject
  132. * @param $prefix
  133. * @param $controllerDescribe
  134. * @param array $permission 权限数组
  135. * @return array 权限数组
  136. */
  137. private static function getActionInController($controllerObject, $prefix, $controllerDescribe, $permission = [])
  138. {
  139. foreach ($controllerObject->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
  140. //action的注释
  141. $actionComment = $method->getDocComment();
  142. $actionPregRes = preg_match("/(?<=ACTION ).*?(?= ACTION)/", $actionComment, $actionDescribe);
  143. if ($actionPregRes) {
  144. $actionName = $method->getName();
  145. if ($actionName != 'actions' && strpos($actionName, 'action') === 0) {
  146. $name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', substr($actionName, 6)));
  147. $id = $prefix . ltrim(str_replace(' ', '-', $name), '-');
  148. $permission[$controllerDescribe[0]][$actionDescribe[0]] = $id;
  149. }
  150. }
  151. }
  152. return $permission;
  153. }
  154. }