| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- <?php
- /**
- * Author: lf
- * Blog: https://blog.feehi.com
- * Email: job@feehi.com
- * Created at: 2018-11-26 12:43
- */
- namespace console\controllers\helpers;
- use Yii;
- use ReflectionClass;
- use yii\base\Exception;
- use yii\helpers\FileHelper;
- class BackendAuth extends \yii\base\BaseObject
- {
- /**
- * @var string Directory where you want to generate RBAC Permission rules, often is backend/controllers
- */
- private $_controllerPath = "@backend/controllers";
- /**
- * @var array a list of $generateRBACControllerPath directory that to need generate controllers
- */
- private $_noNeedRBACControllers = ['AssetsController', 'SiteController'];
- /**
- * @var array a list of none generate RBAc items(execute result, collected the annotations of controller::actions() or controller::actionX())
- */
- private $_noNeedRBACRoutes = [];
- private $_unPropertyDocCommentsRoutes = [];
- private $_authItems = [];
- private $_dbAuthItems = null;
- public $error = null;
- public function init()
- {
- parent::init();
- $this->parseAuthItems();
- }
- public function setControllerPath($controllerPath)
- {
- $this->_controllerPath = $controllerPath;
- }
- public function getControllerPath()
- {
- return Yii::getAlias($this->_controllerPath);
- }
- public function setNoNeedRBACControllers(array $noNeedRbacControllers)
- {
- $this->_noNeedRBACControllers = $noNeedRbacControllers;
- }
- public function getNoNeedRBACControllers()
- {
- return $this->_noNeedRBACControllers;
- }
- public function setNoNeedRBACRoutes($routes)
- {
- $this->_noNeedRBACRoutes = $routes;
- }
- public function getNoNeedRBACRoutes()
- {
- return $this->_noNeedRBACRoutes;
- }
- public function getAuthItems()
- {
- return $this->_authItems;
- }
- public function getDbAuthItems()
- {
- if( $this->_dbAuthItems === null ) {
- $dbAuthItems = Yii::$app->getAuthManager()->getPermissions();
- $this->_dbAuthItems = $dbAuthItems;
- }
- return $this->_dbAuthItems;
- }
- public function setError($error){
- $this->error = $error;
- }
- public function getError()
- {
- return $this->error;
- }
- public function parseControllerPartialUrl($subDirControllerName)
- {
- $subDirControllerName = explode('/', $subDirControllerName);
- $controllerName = str_replace('Controller', '', array_pop($subDirControllerName));
- $controllerTemp = lcfirst($controllerName);
- $controllerString = "";
- for ($i = 0; $i < strlen($controllerTemp); $i++) {
- $str = ord($controllerTemp[$i]);
- if ($str > 64 && $str < 91) {
- $controllerString .= '-' . strtolower($controllerTemp[$i]);
- } else {
- $controllerString .= $controllerTemp[$i];
- }
- }
- $subDirControllerName[] = $controllerString;
- return implode('/', $subDirControllerName);
- }
- public function getActionAuthItemsByDocComment($docComments)
- {
- if( strpos( $docComments, "@auth - item" ) !== false ){
- $temp = explode("@auth", $docComments)[1];
- }else if( strpos( $docComments, "@auth" ) !== false ){
- $temp = explode("@auth", $docComments)[1];
- }else{
- return false;
- }
- if( strpos($temp, '@') !== false ){
- $temp = explode('@', $temp)[0];
- $temp = trim($temp);
- $temp = trim($temp, "*");
- $temp = trim($temp);
- }else{
- $temp = explode('*/', $temp)[0];
- $temp = trim($temp);
- }
- $arr = explode("\n", $temp);
- $authItems = [];
- foreach ($arr as $s) {
- if (strpos($s, '- item') === false) {
- continue;
- };
- $s = explode('- item', $s)[1];
- $s = trim($s);
- $row = explode(" ", $s);
- $authItem = [];
- foreach ($row as $v) {
- $t = explode("=", $v);
- if (isset($t[1])) {
- $authItem[$t[0]] = $t[1];
- }
- }
- if( isset( $authItem['rbac'] ) && ($authItem['rbac'] == 'false' || $authItem['rbac'] == 'no' ) ){
- $authItems[] = $authItem;
- }else {
- $httpMethods = [];
- if( strpos($authItem['method'], ',') !== false ) {
- $httpMethods = explode(',', $authItem['method']);
- foreach ($httpMethods as $key => $httpMethod){
- $httpMethod = trim($httpMethod);
- $httpMethods[$key] = $this->filterAlphabetToLower($httpMethod);
- }
- }else{
- $authItem['method'] = trim($authItem['method']);
- $httpMethod = $this->filterAlphabetToLower($authItem['method']);
- $httpMethods[] = $httpMethod;
- }
- $authItem['methods'] = $httpMethods;
- unset($authItem['method']);
- $authItems[] = $authItem;
- }
- }
- return $authItems;
- }
- public function parseActionPartialUrl($actionName)
- {
- $actionTemp = lcfirst($actionName);
- $actionString = "";
- for ($i = 0; $i < strlen($actionTemp); $i++) {
- $str = ord($actionTemp[$i]);
- if ($str > 64 && $str < 91) {
- $actionString .= '-' . strtolower($actionTemp[$i]);
- } else {
- $actionString .= $actionTemp[$i];
- }
- }
- return $actionString;
- }
- public function parseAuthItems()
- {
- $controllerPath = $this->getControllerPath();
- $files = [];
- foreach (FileHelper::findFiles($controllerPath) as $file) {
- $files[] = str_replace($controllerPath . DIRECTORY_SEPARATOR, '', $file);
- }
- foreach($files as $file ) {
- if( !strpos($file, "Controller") ) continue;
- $subDirControllerName = str_replace('.php', '', $file);
- if (in_array($subDirControllerName, $this->getNoNeedRBACControllers())) {
- Yii::info($subDirControllerName . "不受权限控制,跳过");
- continue;
- }
- $class = new ReflectionClass("\\backend\\controllers\\" . str_replace('/', '\\', $subDirControllerName));
- $controllerPartialUrl = $this->parseControllerPartialUrl($subDirControllerName);
- $methods = $class->getMethods();
- foreach ($methods as $method) {
- $actions = [];
- $authItems = [];
- $actionNum = 0;
- if ($method->getName() === 'actions') {
- $obj = $class->newInstanceArgs([1, 2]);
- $actions = $obj->actions();
- if( empty($actions) ) continue;
- $authItems = $this->getActionAuthItemsByDocComment($method->getDocComment());
- $actionNum = count($actions);
- } else if (strpos($method->getName(), 'action') === 0) {
- $action = str_replace('action', '', $method->getName());
- $authItems = $this->getActionAuthItemsByDocComment($method->getDocComment());
- $actions[$action] = $action;
- $actionNum = 1;
- }
- if (!is_array($authItems)) {
- continue;
- }
- if ( count($authItems) !== $actionNum ) {
- $this->_unPropertyDocCommentsRoutes[] = $controllerPartialUrl;
- $error = "$subDirControllerName::actions或actionX 注释和action数量不匹配 注释(doc comment)数量" . count($authItems) . " 方法(action method)数量" . count($actions) . "(actions or actionX doc comment not equal action method quantity)";
- throw new Exception($error);
- }
- $j = 0;
- foreach ($actions as $action => $none) {
- $actionPartialUrl = $this->parseActionPartialUrl($action);
- $url = '/' . $controllerPartialUrl . '/' . $actionPartialUrl;
- if( isset( $authItems[$j]['rbac'] ) && ( in_array($authItems[$j]['rbac'], ['false', 'no']) ) ){
- $this->_noNeedRBACRoutes[] = $url;
- continue;
- }
- foreach ($authItems[$j]['methods'] as $httpMethod) {
- $httpMethod = strtoupper(trim($httpMethod));
- $description = call_user_func(function()use($httpMethod, $authItems, $j){
- if( isset($authItems[$j]['description-' . strtolower($httpMethod)]) ){
- return $authItems[$j]['description-' . strtolower($httpMethod)];
- }
- switch ($httpMethod){
- case 'GET':
- return $authItems[$j]['description'] . '(查看)';
- case 'POST':
- return $authItems[$j]['description'] . '(确定)';
- }
- });
- $sort = call_user_func(function()use($httpMethod, $authItems, $j){
- if( isset($authItems[$j]['sort-' . strtolower($httpMethod)]) ){
- return $authItems[$j]['sort-' . strtolower($httpMethod)];
- }
- $sort = isset( $authItems[$j]['sort'] ) ? $authItems[$j]['sort'] : 0;
- return $sort;
- });
- $this->_authItems = array_merge($this->_authItems, [[
- 'name' => $url . ':' . $httpMethod,
- 'route' => $url,
- 'description' => $description,
- 'group' => $authItems[$j]['group'],
- 'category' => $authItems[$j]['category'],
- 'method' => $httpMethod,
- 'sort' => $sort,
- ]]);
- }
- $j++;
- }
- }
- }
- }
- private function filterAlphabetToLower($str)
- {
- $alphabet = "";
- for ($i = 0; $i < strlen($str); $i++) {
- $n = ord($str[$i]);
- if ($n > 64 && $n < 123) {
- $alphabet .= strtolower($str[$i]);
- }
- }
- return $alphabet;
- }
- }
|