├── .gitignore ├── LICENSE ├── Modules.php ├── README.md ├── WX20220819-104012@2x.png ├── components ├── AccessControl.php ├── Configs.php ├── DbManager.php ├── GuestRule.php ├── Helper.php ├── ItemController.php ├── MenuHelper.php └── RouteRule.php ├── composer.json ├── controllers ├── AssignmentController.php ├── AuthItemController.php ├── GroupsController.php ├── MenuController.php ├── PermissionController.php ├── RoleController.php ├── RouteController.php ├── RuleController.php ├── SiteController.php ├── UserController.php └── base │ └── ApiController.php ├── example ├── auth_item_sql └── rbac_route.php ├── helper └── RbacHelper.php ├── jetbrains.png ├── migrations ├── m140602_111327_create_menu_table.php ├── m160312_050000_create_user.php ├── schema-mssql.sql ├── schema-mysql.sql ├── schema-oci.sql ├── schema-pgsql.sql └── schema-sqlite.sql ├── models ├── Assignment.php ├── AuthGroups.php ├── AuthGroupsChild.php ├── AuthItem.php ├── BizRule.php ├── Menu.php ├── Permission.php ├── Role.php ├── Route.php ├── User.php ├── form │ └── Login.php └── searchs │ ├── Assignment.php │ ├── AuthItem.php │ ├── BizRule.php │ ├── Menu.php │ └── User.php └── rule └── BelongShopRule.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Windhoney 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Modules.php: -------------------------------------------------------------------------------- 1 | 'left-menu', // default to null mean use application layout. 17 | * 'controllerMap' => [ 18 | * 'assignment' => [ 19 | * 'class' => 'mdm\admin\controllers\AssignmentController', 20 | * 'userClassName' => 'app\models\User', 21 | * 'idField' => 'id' 22 | * ] 23 | * ], 24 | * 'menus' => [ 25 | * 'assignment' => [ 26 | * 'label' => 'Grand Access' // change label 27 | * ], 28 | * 'route' => null, // disable menu 29 | * ], 30 | * ``` 31 | * 32 | * @property string $mainLayout Main layout using for module. Default to layout of parent module. 33 | * Its used when `layout` set to 'left-menu', 'right-menu' or 'top-menu'. 34 | * @property array $menus List avalible menu of module. 35 | * It generated by module items . 36 | * 37 | * @author Misbahul D Munir 38 | * @since 1.0 39 | */ 40 | class Modules extends \yii\base\Module 41 | { 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public $controllerNamespace = 'wind\rest\controllers'; 47 | 48 | /** 49 | * @var array Nav bar items. 50 | */ 51 | public $navbar; 52 | // /** 53 | // * @var string Main layout using for module. Default to layout of parent module. 54 | // * Its used when `layout` set to 'left-menu', 'right-menu' or 'top-menu'. 55 | // */ 56 | // public $mainLayout = '@mdm/admin/views/layouts/main.php'; 57 | /** 58 | * @var array 59 | * @see [[menus]] 60 | */ 61 | private $_menus = []; 62 | /** 63 | * @var array 64 | * @see [[menus]] 65 | */ 66 | private $_coreItems = [ 67 | 'user' => 'Users', 68 | 'assignment' => 'Assignments', 69 | 'role' => 'Roles', 70 | 'permission' => 'Permissions', 71 | 'route' => 'Routes', 72 | 'rule' => 'Rules', 73 | 'menu' => 'Menus', 74 | ]; 75 | /** 76 | * @var array 77 | * @see [[items]] 78 | */ 79 | private $_normalizeMenus; 80 | 81 | /** 82 | * @var string Default url for breadcrumb 83 | */ 84 | public $defaultUrl; 85 | 86 | /** 87 | * @var string Default url label for breadcrumb 88 | */ 89 | public $defaultUrlLabel; 90 | 91 | /** 92 | * @inheritdoc 93 | */ 94 | public function init() 95 | { 96 | parent::init(); 97 | // if (!isset(Yii::$app->i18n->translations['rbac-admin'])) { 98 | // Yii::$app->i18n->translations['rbac-admin'] = [ 99 | // 'class' => 'yii\i18n\PhpMessageSource', 100 | // 'sourceLanguage' => 'en', 101 | // 'basePath' => '@mdm/admin/messages' 102 | // ]; 103 | // } 104 | $userClass = ArrayHelper::getValue(Yii::$app->components, 'user.identityClass'); 105 | if ($this->defaultRoute == 'default' && $userClass && is_subclass_of($userClass, 'yii\db\BaseActiveRecord')) { 106 | $this->defaultRoute = 'assignment'; 107 | } 108 | } 109 | 110 | /** 111 | * Get avalible menu. 112 | * @return array 113 | */ 114 | public function getMenus() 115 | { 116 | if ($this->_normalizeMenus === null) { 117 | $mid = '/' . $this->getUniqueId() . '/'; 118 | // resolve core menus 119 | $this->_normalizeMenus = []; 120 | 121 | $config = components\Configs::instance(); 122 | $conditions = [ 123 | 'user' => $config->db && $config->db->schema->getTableSchema($config->userTable), 124 | 'assignment' => ($userClass = Yii::$app->getUser()->identityClass) && is_subclass_of($userClass, 'yii\db\BaseActiveRecord'), 125 | 'menu' => $config->db && $config->db->schema->getTableSchema($config->menuTable), 126 | ]; 127 | foreach ($this->_coreItems as $id => $lable) { 128 | if (!isset($conditions[$id]) || $conditions[$id]) { 129 | $this->_normalizeMenus[$id] = ['label' => Yii::t('rbac-admin', $lable), 'url' => [$mid . $id]]; 130 | } 131 | } 132 | foreach (array_keys($this->controllerMap) as $id) { 133 | $this->_normalizeMenus[$id] = ['label' => Yii::t('rbac-admin', Inflector::humanize($id)), 'url' => [$mid . $id]]; 134 | } 135 | 136 | // user configure menus 137 | foreach ($this->_menus as $id => $value) { 138 | if (empty($value)) { 139 | unset($this->_normalizeMenus[$id]); 140 | continue; 141 | } 142 | if (is_string($value)) { 143 | $value = ['label' => $value]; 144 | } 145 | $this->_normalizeMenus[$id] = isset($this->_normalizeMenus[$id]) ? array_merge($this->_normalizeMenus[$id], $value) 146 | : $value; 147 | if (!isset($this->_normalizeMenus[$id]['url'])) { 148 | $this->_normalizeMenus[$id]['url'] = [$mid . $id]; 149 | } 150 | } 151 | } 152 | return $this->_normalizeMenus; 153 | } 154 | 155 | /** 156 | * Set or add avalible menu. 157 | * @param array $menus 158 | */ 159 | public function setMenus($menus) 160 | { 161 | $this->_menus = array_merge($this->_menus, $menus); 162 | $this->_normalizeMenus = null; 163 | } 164 | 165 | /** 166 | * @inheritdoc 167 | */ 168 | public function beforeAction($action) 169 | { 170 | if (parent::beforeAction($action)) { 171 | return true; 172 | } 173 | return false; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yii2-rest-rbac 2 | **感谢JetBrains对开源软件的支持**[![JetBrains Logo](jetbrains.png)](https://www.jetbrains.com/?from=yii2-rest-rbac) 3 | 4 | > Yii2权限系统,rest版,根据[yii2-admin(https://github.com/mdmsoft/yii2-admin)](https://github.com/mdmsoft/yii2-admin)修改 5 | 6 | * **安装:** 7 | ```php 8 | 9 | composer require windhoney/yii2-rest-rbac 10 | ``` 11 | 12 | ### **使用** 13 | 14 | * **配置oauth2和rbac** 15 | ```php 16 | 'modules' => [ 17 | 'rbac' => [ 18 | 'class' => 'wind\rest\Modules' 19 | ], 20 | 'oauth2' => [ 21 | 'class' => 'filsh\yii2\oauth2server\Module', 22 | //'class' => 'wind\oauth2\Module',相对filsh\yii2\oauth2server做了一点优化,增加了可修改oauth2表的db name 23 | 'tokenParamName' => 'access_token', 24 | 'tokenAccessLifetime' => 3600 * 24, 25 | 'storageMap' => [ 26 | 'user_credentials' => 'common\models\User',//可自定义 27 | ], 28 | 'grantTypes' => [ 29 | 'user_credentials' => [ 30 | 'class' => 'OAuth2\GrantType\UserCredentials', 31 | ], 32 | 'client_credentials' => [ 33 | 'class' => 'OAuth2\GrantType\ClientCredentials', 34 | ], 35 | 'refresh_token' => [ 36 | 'class' => 'OAuth2\GrantType\RefreshToken', 37 | 'always_issue_new_refresh_token' => true 38 | ], 39 | 'authorization_code' => [ 40 | 'class' => 'OAuth2\GrantType\AuthorizationCode' 41 | ], 42 | ], 43 | //选填,oauth2组件版本问题可能导致错误时可添加 44 | 'components' => [ 45 | 'request' => function () { 46 | return \filsh\yii2\oauth2server\Request::createFromGlobals(); 47 | }, 48 | 'response' => [ 49 | 'class' => \filsh\yii2\oauth2server\Response::class, 50 | ], 51 | ], 52 | ] 53 | ], 54 | 'components' => [ 55 | 'authManager' => [ 56 | 'class' => 'wind\rest\components\DbManager', //配置文件 57 | 'defaultRoles' => ['普通员工'] //选填,默认角色(默认角色下->公共权限(登陆,oauth2,首页等公共页面)) 58 | 'groupTable' => 'auth_groups',//选填,分组表(已默认,可根据自己表名修改) 59 | 'groupChildTable' => 'auth_groups_child',//选填,分组子表(已默认,可根据自己表名修改) 60 | ], 61 | 'request' => [ 62 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 63 | //'cookieValidationKey' => 'xxxxxxxx', 64 | 'parsers' => [ 65 | 'application/json' => 'yii\web\JsonParser', 66 | 'text/json' => 'yii\web\JsonParser', 67 | ], 68 | ], 69 | ] 70 | ``` 71 | * **配置权限** 72 | 73 | ```php 74 | 'as access' => [ 75 | 'class' => 'wind\rest\components\AccessControl', 76 | 'allowActions' => [ 77 | 'site/*',//允许访问的节点,可自行添加 78 | 'rbac/menu/user-menu',//可将路由配置到“普通员工”(默认角色)下 79 | 'oauth2/*',//可将路由配置到“普通员工”(默认角色)下 80 | ] 81 | ], 82 | ``` 83 | 84 | 85 | * **创建所需要的表** 86 | > ###### 1. 用户表user和菜单表menu 87 | ```php 88 | yii migrate --migrationPath=@vendor/windhoney/yii2-rest-rbac/migrations 89 | ``` 90 | > ###### 2. rbac相关权限表 91 | ```php 92 | yii migrate --migrationPath=@yii/rbac/migrations/ 93 | ``` 94 | 95 | > **`auth_item` 表添加一个字段 `parent_name` varchar(30) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '父级名称'**, 96 | ###### 3. oauth2相关表 97 | 98 | ```php 99 | yii migrate --migrationPath=@vendor/filsh/yii2-oauth2-server/migrations 100 | ``` 101 | 102 | > ###### 4. 新增分组表 103 | 104 | ```mysql 105 | CREATE TABLE `auth_groups` ( 106 | `group_id` varchar(50) NOT NULL COMMENT '分组id', 107 | `group_name` varchar(100) NOT NULL DEFAULT '' COMMENT '分组名称', 108 | `group_status` varchar(50) NOT NULL DEFAULT '' COMMENT '状态(开启,关闭)', 109 | PRIMARY KEY (`group_id`) 110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='分组'; 111 | ``` 112 | 113 | ```mysql 114 | CREATE TABLE `auth_groups_child` ( 115 | `id` int(11) NOT NULL AUTO_INCREMENT, 116 | `group_id` varchar(50) NOT NULL COMMENT '分组id', 117 | `user_id` varchar(64) NOT NULL COMMENT '用户id', 118 | PRIMARY KEY (`id`), 119 | UNIQUE KEY `group_id_2` (`group_id`,`user_id`), 120 | KEY `group_id` (`group_id`), 121 | KEY `user_group_id` (`user_id`) USING BTREE 122 | ) ENGINE=InnoDB AUTO_INCREMENT=795 DEFAULT CHARSET=utf8 COMMENT='分组子集'; 123 | ``` 124 | > ###### 5. 权限控制相关路由可以参考 example/auth_item_sql 其中包含权限相关的insert语句 125 | 126 | ```mysql 127 | INSERT INTO `auth_item` (`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/index', '2', '接口-菜单接口', NULL, '权限控制', '', '1526377735', '1526377269'); 128 | INSERT INTO `auth_item` (`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/index', '2', '接口-角色接口', NULL, '权限控制', '', '1526377735', '1526377269'); 129 | ...... 130 | ``` 131 | 132 | 133 | * **添加路由配置** 134 | 135 | > * 将yii2-rest-rbac/example/rbac_route.php文件内容配置到项目的urlManager的rules规则下 136 | > * 或者在main.php文件中 添加 137 | ```php 138 | $dir = __DIR__ . "/route"; 139 | $main = wind\rest\helper\RbacHelper::addRoute($dir, $main); 140 | return $main; 141 | ``` 142 | >> 并将此文件放到config/route/rbac_route.php 143 | 144 | * **接口文档参考** 145 | 146 | * [文档](https://windhoney.gitbook.io/yii2-rest-rbac/) 147 | 148 | 149 | -------------------------------------------------------------------------------- /WX20220819-104012@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windhoney/yii2-rest-rbac/f04e4d9f99cbe7710e687b337b906615e46775d9/WX20220819-104012@2x.png -------------------------------------------------------------------------------- /components/AccessControl.php: -------------------------------------------------------------------------------- 1 | [ 22 | * 'class' => 'wind\rest\components\AccessControl', 23 | * 'allowActions' => ['site/login', 'site/error'] 24 | * ] 25 | * ``` 26 | * 27 | * @property User $user 28 | */ 29 | class AccessControl extends \yii\base\ActionFilter 30 | { 31 | /** 32 | * @var User User for check access. 33 | */ 34 | private $_user = 'user'; 35 | /** 36 | * @var array List of action that not need to check access. 37 | */ 38 | public $allowActions = []; 39 | 40 | /** 41 | * Get user 42 | * 43 | * @return User 44 | */ 45 | public function getUser() 46 | { 47 | if (!$this->_user instanceof User) { 48 | $this->_user = Instance::ensure($this->_user, User::className()); 49 | } 50 | return $this->_user; 51 | } 52 | 53 | /** 54 | * Set user 55 | * @param User|string $user 56 | */ 57 | public function setUser($user) 58 | { 59 | $this->_user = $user; 60 | } 61 | 62 | /** 63 | * @inheritdoc 64 | */ 65 | public function beforeAction($action) 66 | { 67 | $actionId = $action->getUniqueId(); 68 | $user = $this->getUser(); 69 | if (Helper::checkRoute('/' . $actionId, Yii::$app->getRequest()->get(), $user)) { 70 | return true; 71 | } 72 | $this->denyAccess($user); 73 | } 74 | 75 | /** 76 | * Denies the access of the user. 77 | * The default implementation will redirect the user to the login page if he is a guest; 78 | * if the user is already logged, a 403 HTTP exception will be thrown. 79 | * @param User $user the current user 80 | * @throws ForbiddenHttpException if the user is already logged in. 81 | */ 82 | protected function denyAccess($user) 83 | { 84 | if ($user->getIsGuest()) { 85 | throw new UnauthorizedHttpException(Yii::t('yii', 'Login Required')); 86 | } else { 87 | throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.')); 88 | } 89 | } 90 | 91 | /** 92 | * @inheritdoc 93 | */ 94 | protected function isActive($action) 95 | { 96 | $uniqueId = $action->getUniqueId(); 97 | if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) { 98 | return false; 99 | } 100 | 101 | $user = $this->getUser(); 102 | if ($user->getIsGuest() && is_array($user->loginUrl) && isset($user->loginUrl[0]) && $uniqueId === trim($user->loginUrl[0], '/')) { 103 | return false; 104 | } 105 | 106 | if ($this->owner instanceof Module) { 107 | // convert action uniqueId into an ID relative to the module 108 | $mid = $this->owner->getUniqueId(); 109 | $id = $uniqueId; 110 | if ($mid !== '' && strpos($id, $mid . '/') === 0) { 111 | $id = substr($id, strlen($mid) + 1); 112 | } 113 | } else { 114 | $id = $action->id; 115 | } 116 | 117 | foreach ($this->allowActions as $route) { 118 | if (substr($route, -1) === '*') { 119 | $route = rtrim($route, "*"); 120 | if ($route === '' || strpos($id, $route) === 0) { 121 | return false; 122 | } 123 | } else { 124 | if ($id === $route) { 125 | return false; 126 | } 127 | } 128 | } 129 | 130 | if ($action->controller->hasMethod('allowAction') && in_array($action->id, $action->controller->allowAction())) { 131 | return false; 132 | } 133 | 134 | return true; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /components/Configs.php: -------------------------------------------------------------------------------- 1 | [ 21 | * 'db' => 'customDb', 22 | * 'menuTable' => '{{%admin_menu}}', 23 | * 'cache' => [ 24 | * 'class' => 'yii\caching\DbCache', 25 | * 'db' => ['dsn' => 'sqlite:@runtime/admin-cache.db'], 26 | * ], 27 | * ] 28 | * ]; 29 | * ``` 30 | * 31 | * or use [[\Yii::$container]] 32 | * 33 | * ``` 34 | * Yii::$container->set('wind\rest\components\Configs',[ 35 | * 'db' => 'customDb', 36 | * 'menuTable' => 'admin_menu', 37 | * ]); 38 | * ``` 39 | */ 40 | class Configs extends BaseObject 41 | { 42 | 43 | const CACHE_TAG = 'wind.rest'; 44 | 45 | /** 46 | * @var Connection Database connection. 47 | */ 48 | public $db = 'db'; 49 | /** 50 | * @var Cache Cache component. 51 | */ 52 | public $cache = 'cache'; 53 | /** 54 | * @var integer Cache duration. Default to a hour. 55 | */ 56 | public $cacheDuration = 3600; 57 | /** 58 | * @var string Menu table name. 59 | */ 60 | public $menuTable = '{{%menu}}'; 61 | /** 62 | * @var string user table name. 63 | */ 64 | public $userTable = '{{%user}}'; 65 | /** 66 | * @var integer Default status user signup. 10 mean active. 67 | */ 68 | public $defaultUserStatus = 10; 69 | /** 70 | * @var boolean If true then AccessControl only check if route are registered. 71 | */ 72 | public $onlyRegisteredRoute = false; 73 | /** 74 | * @var boolean If false then AccessControl will check without Rule. 75 | */ 76 | public $strict = true; 77 | /** 78 | * @var array 79 | */ 80 | public $options; 81 | /** 82 | * @var self Instance of self 83 | */ 84 | private static $_instance; 85 | private static $_classes = [ 86 | 'db' => 'yii\db\Connection', 87 | 'cache' => 'yii\caching\Cache', 88 | ]; 89 | 90 | /** 91 | * @inheritdoc 92 | */ 93 | public function init() 94 | { 95 | foreach (self::$_classes as $key => $class) { 96 | try { 97 | $this->{$key} = empty($this->{$key}) ? null : Instance::ensure($this->{$key}, $class); 98 | } catch (\Exception $exc) { 99 | $this->{$key} = null; 100 | Yii::error($exc->getMessage()); 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * Create instance of self 107 | * 108 | * @return static 109 | */ 110 | public static function instance() 111 | { 112 | if (self::$_instance === null) { 113 | $type = ArrayHelper::getValue(Yii::$app->params, 'mdm.admin.configs', []); 114 | if (is_array($type) && !isset($type['class'])) { 115 | $type['class'] = static::className(); 116 | } 117 | 118 | return self::$_instance = Yii::createObject($type); 119 | } 120 | 121 | return self::$_instance; 122 | } 123 | 124 | public static function __callStatic($name, $arguments) 125 | { 126 | $instance = static::instance(); 127 | if ($instance->hasProperty($name)) { 128 | return $instance->$name; 129 | } else { 130 | if (count($arguments)) { 131 | $instance->options[$name] = reset($arguments); 132 | } else { 133 | return array_key_exists($name, $instance->options) ? $instance->options[$name] : null; 134 | } 135 | } 136 | } 137 | 138 | /** 139 | * @return Connection 140 | */ 141 | public static function db() 142 | { 143 | return static::instance()->db; 144 | } 145 | 146 | /** 147 | * @return Cache 148 | */ 149 | public static function cache() 150 | { 151 | return static::instance()->cache; 152 | } 153 | 154 | /** 155 | * @return integer 156 | */ 157 | public static function cacheDuration() 158 | { 159 | return static::instance()->cacheDuration; 160 | } 161 | 162 | /** 163 | * @return string 164 | */ 165 | public static function menuTable() 166 | { 167 | return static::instance()->menuTable; 168 | } 169 | 170 | /** 171 | * @return string 172 | */ 173 | public static function userTable() 174 | { 175 | return static::instance()->userTable; 176 | } 177 | 178 | /** 179 | * @return string 180 | */ 181 | public static function defaultUserStatus() 182 | { 183 | return static::instance()->defaultUserStatus; 184 | } 185 | 186 | /** 187 | * @return boolean 188 | */ 189 | public static function onlyRegisteredRoute() 190 | { 191 | return static::instance()->onlyRegisteredRoute; 192 | } 193 | 194 | /** 195 | * @return boolean 196 | */ 197 | public static function strict() 198 | { 199 | return static::instance()->strict; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /components/DbManager.php: -------------------------------------------------------------------------------- 1 | 27 | * @since 1.0 28 | */ 29 | class DbManager extends \yii\rbac\DbManager 30 | { 31 | 32 | /** 33 | * @var Connection|array|string the DB connection object or the application component ID of the DB connection. 34 | * After the DbManager object is created, if you want to change this property, you should only assign it 35 | * with a DB connection object. 36 | * Starting from version 2.0.2, this can also be a configuration array for creating the object. 37 | */ 38 | public $db = 'db'; 39 | /** 40 | * @var string the name of the table storing authorization items. Defaults to "auth_item". 41 | */ 42 | public $itemTable = 'auth_item'; 43 | /** 44 | * @var string the name of the table storing authorization item hierarchy. Defaults to "auth_item_child". 45 | */ 46 | public $itemChildTable = 'auth_item_child'; 47 | /** 48 | * @var string the name of the table storing authorization item assignments. Defaults to "auth_assignment". 49 | */ 50 | public $assignmentTable = 'auth_assignment'; 51 | /** 52 | * @var string the name of the table storing rules. Defaults to "auth_rule". 53 | */ 54 | public $ruleTable = 'auth_rule'; 55 | /** 56 | * @var string the name of the table storing groups. Defaults to "auth_groups". 57 | */ 58 | public $groupTable = 'auth_groups'; 59 | /** 60 | * @var string the name of the table storing groups. Defaults to "auth_groups_child". 61 | */ 62 | public $groupChildTable = 'auth_groups_child'; 63 | /** 64 | * @var Connection|array|string the DB connection object or the application component ID of the DB connection. 65 | * After the DbManager object is created, if you want to change this property, you should only assign it 66 | * with a DB connection object. 67 | * Starting from version 2.0.2, this can also be a configuration array for creating the object. 68 | */ 69 | // public $db = 'db'; 70 | /** 71 | * Memory cache of assignments 72 | * 73 | * @var array 74 | */ 75 | private $_assignments = []; 76 | private $_childrenList; 77 | 78 | /** 79 | * @inheritdoc 80 | */ 81 | public function getAssignments($userId) 82 | { 83 | if ( !isset($this->_assignments[$userId])) { 84 | $this->_assignments[$userId] = parent::getAssignments($userId); 85 | } 86 | 87 | return $this->_assignments[$userId]; 88 | } 89 | 90 | /** 91 | * @inheritdoc 92 | */ 93 | protected function getChildrenList() 94 | { 95 | if ($this->_childrenList === null) { 96 | $this->_childrenList = parent::getChildrenList(); 97 | } 98 | 99 | return $this->_childrenList; 100 | } 101 | 102 | /** 103 | * Populates an auth item with the data fetched from database 104 | * 105 | * @param array $row the data from the auth item table 106 | * 107 | * @return Item the populated auth item instance (either Role or Permission) 108 | */ 109 | protected function populateItem($row) 110 | { 111 | $class = $row['type'] == Item::TYPE_PERMISSION ? \wind\rest\models\Permission::className() : \wind\rest\models\Role::className(); 112 | 113 | if ( !isset($row['data']) || ($data = @unserialize($row['data'])) === false) { 114 | $data = null; 115 | } 116 | 117 | return new $class([ 118 | 'name' => $row['name'], 119 | 'type' => $row['type'], 120 | 'description' => $row['description'], 121 | 'parent_name' => $row['parent_name'], 122 | 'ruleName' => $row['rule_name'], 123 | 'data' => $data, 124 | 'createdAt' => $row['created_at'], 125 | 'updatedAt' => $row['updated_at'], 126 | ]); 127 | } 128 | 129 | /** 130 | * @inheritdoc 131 | */ 132 | public function getChildren($name) 133 | { 134 | $query = (new Query) 135 | ->select(['name', 'type', 'description', 'rule_name', 'parent_name', 'data', 'created_at', 'updated_at']) 136 | ->from([$this->itemTable, $this->itemChildTable]) 137 | ->where(['parent' => $name, 'name' => new Expression('[[child]]')]); 138 | 139 | $children = []; 140 | foreach ($query->all($this->db) as $row) { 141 | $children[$row['name']] = $this->populateItem($row); 142 | } 143 | 144 | return $children; 145 | } 146 | 147 | /** 148 | * @inheritdoc 149 | */ 150 | protected function addItem($item) 151 | { 152 | $time = time(); 153 | if ($item->createdAt === null) { 154 | $item->createdAt = $time; 155 | } 156 | if ($item->updatedAt === null) { 157 | $item->updatedAt = $time; 158 | } 159 | $this->db->createCommand() 160 | ->insert($this->itemTable, [ 161 | 'name' => $item->name, 162 | 'type' => $item->type, 163 | 'description' => $item->description, 164 | 'parent_name' => $item->parent_name ?? '', 165 | 'rule_name' => $item->ruleName, 166 | 'data' => $item->data === null ? null : serialize($item->data), 167 | 'created_at' => $item->createdAt, 168 | 'updated_at' => $item->updatedAt, 169 | ])->execute(); 170 | 171 | $this->invalidateCache(); 172 | 173 | return true; 174 | } 175 | 176 | /** 177 | * @inheritdoc 178 | */ 179 | public function createPermission($name) 180 | { 181 | $permission = new \wind\rest\models\Permission(); 182 | $permission->name = $name; 183 | 184 | return $permission; 185 | } 186 | 187 | /** 188 | * 路由父级名称 189 | * 190 | * @return array 191 | */ 192 | public function getRouteParent() 193 | { 194 | $query = (new Query) 195 | ->select('parent_name') 196 | ->from([$this->itemTable]) 197 | ->distinct() 198 | ->where('parent_name is not null'); 199 | return $query->all($this->db); 200 | } 201 | 202 | 203 | public function getAssignmentsUsers($item) 204 | { 205 | $query = (new Query) 206 | ->select(['id', 'realname']) 207 | ->from([$this->assignmentTable]) 208 | ->leftJoin(Configs::instance()->userTable, $this->assignmentTable . '.user_id=id') 209 | ->andWhere(['status' => 10]) 210 | ->andWhere(['item_name' => $item]); 211 | return $query->all($this->db); 212 | } 213 | 214 | /** 215 | * 分组列表 216 | * 217 | * @return array 218 | */ 219 | public function getGroups($group_name = null) 220 | { 221 | $query = (new Query) 222 | ->select(['group_id', 'group_name']) 223 | ->from([$this->groupTable]) 224 | ->andFilterWhere(['group_name' => $group_name]) 225 | ->andWhere(['group_status' => 0]); 226 | 227 | return $query->all($this->db); 228 | } 229 | 230 | /** 231 | * 用户所在组 232 | * 233 | * @param $user_id 234 | * 235 | * @return array 236 | */ 237 | public function getGroupChild($user_id) 238 | { 239 | $query = (new Query) 240 | ->select(['group_id']) 241 | ->from([$this->groupChildTable]) 242 | ->andWhere(['user_id' => $user_id]); 243 | 244 | return $query->all($this->db); 245 | } 246 | 247 | /** 248 | * 添加分组下用户 249 | * 250 | * @param $data 251 | * 252 | * @return bool 253 | */ 254 | public function assignGroup($group_id, $user_id) 255 | { 256 | $this->db->createCommand() 257 | ->insert($this->groupChildTable, [ 258 | 'group_id' => $group_id, 259 | 'user_id' => $user_id 260 | ])->execute(); 261 | 262 | return true; 263 | } 264 | 265 | /** 266 | * 添加分组下用户 267 | * 268 | * @param $data 269 | * 270 | * @return bool 271 | */ 272 | public function revokeGroup($group_id, $user_id) 273 | { 274 | $this->db->createCommand() 275 | ->delete($this->groupChildTable, [ 276 | 'group_id' => $group_id, 277 | 'user_id' => $user_id 278 | ])->execute(); 279 | 280 | return true; 281 | } 282 | 283 | /** 284 | * @inheritdoc 285 | */ 286 | protected function getItems($type) 287 | { 288 | $query = (new Query) 289 | ->from($this->itemTable) 290 | ->orderBy(['updated_at'=>SORT_DESC]) 291 | ->where(['type' => $type]); 292 | 293 | $items = []; 294 | foreach ($query->all($this->db) as $row) { 295 | $items[$row['name']] = $this->populateItem($row); 296 | } 297 | 298 | return $items; 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /components/GuestRule.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 2.5 12 | */ 13 | class GuestRule extends Rule 14 | { 15 | /** 16 | * @inheritdoc 17 | */ 18 | public $name = 'guest_rule'; 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | public function execute($user, $item, $params) 24 | { 25 | return $user->getIsGuest(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /components/Helper.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 2.3 16 | */ 17 | class Helper 18 | { 19 | 20 | private static $_userRoutes = []; 21 | private static $_defaultRoutes; 22 | private static $_routes; 23 | 24 | public static function getRegisteredRoutes() 25 | { 26 | if (self::$_routes === null) { 27 | self::$_routes = []; 28 | $manager = Yii::$app->getAuthManager(); 29 | foreach ($manager->getPermissions() as $item) { 30 | if ($item->name[0] === '/') { 31 | self::$_routes[$item->name] = $item->name; 32 | } 33 | } 34 | } 35 | 36 | return self::$_routes; 37 | } 38 | 39 | /** 40 | * Get assigned routes by default roles 41 | * 42 | * @return array 43 | */ 44 | protected static function getDefaultRoutes() 45 | { 46 | if (self::$_defaultRoutes === null) { 47 | $manager = Yii::$app->getAuthManager(); 48 | $roles = $manager->defaultRoles; 49 | $cache = Configs::cache(); 50 | if ($cache && ($routes = $cache->get($roles)) !== false) { 51 | self::$_defaultRoutes = $routes; 52 | } else { 53 | $permissions = self::$_defaultRoutes = []; 54 | foreach ($roles as $role) { 55 | $permissions = array_merge($permissions, $manager->getPermissionsByRole($role)); 56 | } 57 | foreach ($permissions as $item) { 58 | if ($item->name[0] === '/') { 59 | self::$_defaultRoutes[$item->name] = true; 60 | } 61 | } 62 | if ($cache) { 63 | $cache->set($roles, self::$_defaultRoutes, Configs::cacheDuration(), new TagDependency([ 64 | 'tags' => Configs::CACHE_TAG 65 | ])); 66 | } 67 | } 68 | } 69 | 70 | return self::$_defaultRoutes; 71 | } 72 | 73 | /** 74 | * Get assigned routes of user. 75 | * 76 | * @param integer $userId 77 | * 78 | * @return array 79 | */ 80 | public static function getRoutesByUser($userId) 81 | { 82 | if ( !isset(self::$_userRoutes[$userId])) { 83 | $cache = Configs::cache(); 84 | if ($cache && ($routes = $cache->get([__METHOD__, $userId])) !== false) { 85 | self::$_userRoutes[$userId] = $routes; 86 | } else { 87 | $routes = static::getDefaultRoutes(); 88 | $manager = Yii::$app->getAuthManager(); 89 | foreach ($manager->getPermissionsByUser($userId) as $item) { 90 | if ($item->name[0] === '/') { 91 | $routes[$item->name] = true; 92 | } 93 | } 94 | self::$_userRoutes[$userId] = $routes; 95 | if ($cache) { 96 | $cache->set([__METHOD__, $userId], $routes, Configs::cacheDuration(), new TagDependency([ 97 | 'tags' => Configs::CACHE_TAG 98 | ])); 99 | } 100 | } 101 | } 102 | 103 | return self::$_userRoutes[$userId]; 104 | } 105 | 106 | /** 107 | * Check access route for user. 108 | * 109 | * @param string|array $route 110 | * @param integer|User $user 111 | * 112 | * @return boolean 113 | */ 114 | public static function checkRoute($route, $params = [], $user = null) 115 | { 116 | $config = Configs::instance(); 117 | $r = static::normalizeRoute($route); 118 | if ($config->onlyRegisteredRoute && !isset(static::getRegisteredRoutes()[$r])) { 119 | return true; 120 | } 121 | 122 | if ($user === null) { 123 | $user = Yii::$app->getUser(); 124 | } 125 | $userId = $user instanceof User ? $user->getId() : $user; 126 | 127 | if ($config->strict) { 128 | if ($user->can($r, $params)) { 129 | return true; 130 | } 131 | while (($pos = strrpos($r, '/')) > 0) { 132 | $r = substr($r, 0, $pos); 133 | if ($user->can($r . '/*', $params)) { 134 | return true; 135 | } 136 | } 137 | 138 | return $user->can('/*', $params); 139 | } else { 140 | $routes = static::getRoutesByUser($userId); 141 | if (isset($routes[$r])) { 142 | return true; 143 | } 144 | while (($pos = strrpos($r, '/')) > 0) { 145 | $r = substr($r, 0, $pos); 146 | if (isset($routes[$r . '/*'])) { 147 | return true; 148 | } 149 | } 150 | 151 | return isset($routes['/*']); 152 | } 153 | } 154 | 155 | protected static function normalizeRoute($route) 156 | { 157 | if ($route === '') { 158 | return '/' . Yii::$app->controller->getRoute(); 159 | } elseif (strncmp($route, '/', 1) === 0) { 160 | return $route; 161 | } elseif (strpos($route, '/') === false) { 162 | return '/' . Yii::$app->controller->getUniqueId() . '/' . $route; 163 | } elseif (($mid = Yii::$app->controller->module->getUniqueId()) !== '') { 164 | return '/' . $mid . '/' . $route; 165 | } 166 | 167 | return '/' . $route; 168 | } 169 | 170 | /** 171 | * Filter menu items 172 | * 173 | * @param array $items 174 | * @param integer|User $user 175 | */ 176 | public static function filter($items, $user = null) 177 | { 178 | if ($user === null) { 179 | $user = Yii::$app->getUser(); 180 | } 181 | 182 | return static::filterRecursive($items, $user); 183 | } 184 | 185 | /** 186 | * Filter menu recursive 187 | * 188 | * @param array $items 189 | * @param integer|User $user 190 | * 191 | * @return array 192 | */ 193 | protected static function filterRecursive($items, $user) 194 | { 195 | $result = []; 196 | foreach ($items as $i => $item) { 197 | $url = ArrayHelper::getValue($item, 'url', '#'); 198 | $allow = is_array($url) ? static::checkRoute($url[0], array_slice($url, 1), $user) : true; 199 | 200 | if (isset($item['items']) && is_array($item['items'])) { 201 | $subItems = self::filterRecursive($item['items'], $user); 202 | if (count($subItems)) { 203 | $allow = true; 204 | } 205 | $item['items'] = $subItems; 206 | } 207 | if ($allow) { 208 | $result[$i] = $item; 209 | } 210 | } 211 | 212 | return $result; 213 | } 214 | 215 | /** 216 | * Filter action column button. Use with [[yii\grid\GridView]] 217 | * ```php 218 | * 'columns' => [ 219 | * ... 220 | * [ 221 | * 'class' => 'yii\grid\ActionColumn', 222 | * 'template' => Helper::filterActionColumn(['view','update','activate']) 223 | * ] 224 | * ], 225 | * ``` 226 | * 227 | * @param array|string $buttons 228 | * @param integer|User $user 229 | * 230 | * @return string 231 | */ 232 | public static function filterActionColumn($buttons = [], $user = null) 233 | { 234 | if (is_array($buttons)) { 235 | $result = []; 236 | foreach ($buttons as $button) { 237 | if (static::checkRoute($button, [], $user)) { 238 | $result[] = "{{$button}}"; 239 | } 240 | } 241 | 242 | return implode(' ', $result); 243 | } 244 | 245 | return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($user) { 246 | return static::checkRoute($matches[1], [], $user) ? "{{$matches[1]}}" : ''; 247 | }, $buttons); 248 | } 249 | 250 | /** 251 | * Use to invalidate cache. 252 | */ 253 | public static function invalidate() 254 | { 255 | if (Configs::cache() !== null) { 256 | TagDependency::invalidate(Configs::cache(), Configs::CACHE_TAG); 257 | } 258 | } 259 | 260 | /** 261 | * 返回auth_rule 表中的店铺的数据权限的 description 262 | */ 263 | public static function get_shops() 264 | { 265 | $user_id = Yii::$app->getUser()->id; 266 | $role_obj = Yii::$app->getAuthManager()->getAssignments($user_id); 267 | $shop_id = ''; 268 | foreach ($role_obj as $role => $obj) { 269 | $role_name = Yii::$app->getAuthManager()->getRole($role); 270 | $shop_id .= isset($role_name->description) ? $role_name->description . ',' : ''; 271 | } 272 | 273 | $shop_id = rtrim($shop_id, ','); 274 | 275 | return $shop_id; 276 | } 277 | 278 | /** 279 | * 树形格式化数据 280 | * 281 | * @param array $list 数据 282 | * @param string $pk 主 283 | * @param string $pid 父 284 | * @param string $child 子集变量名 285 | * @param int $root 根节点 286 | * 287 | * @return array 288 | */ 289 | public static function makeTree($list, $pk = 'id', $pid = 'pid', $child = 'child', $root = 0) 290 | { 291 | $tree = array(); 292 | $packData = array(); 293 | foreach ($list as $data) { 294 | $packData[$data[$pk]] = $data; 295 | } 296 | foreach ($packData as $key => $val) { 297 | if ($val[$pid] == $root) { 298 | //代表根节点 299 | $tree[] =& $packData[$key]; 300 | } else { 301 | //找到其父类 302 | $packData[$val[$pid]][$child][] =& $packData[$key]; 303 | } 304 | } 305 | 306 | return $tree; 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /components/ItemController.php: -------------------------------------------------------------------------------- 1 | 21 | * @since 1.0 22 | */ 23 | class ItemController extends ApiController 24 | { 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public function behaviors() 30 | { 31 | return ArrayHelper::merge(parent::behaviors(), [ 32 | 'verbs' => [ 33 | 'class' => VerbFilter::className(), 34 | 'actions' => [ 35 | 'assign' => ['post', 'get'], 36 | 'remove' => ['post'], 37 | ], 38 | ], 39 | ]); 40 | } 41 | 42 | /** @type \wind\rest\models\AuthItem $auth_item_model */ 43 | public $auth_item_model; 44 | 45 | public function init() 46 | { 47 | parent::init(); 48 | $this->auth_item_model = new AuthItem(); 49 | } 50 | 51 | /** 52 | * 列表 53 | * 54 | * @return mixed 55 | */ 56 | public function actionIndex() 57 | { 58 | $searchModel = new AuthItemSearch(['type' => $this->type]); 59 | $res = $searchModel->search(Yii::$app->request->getQueryParams()); 60 | 61 | return $res; 62 | } 63 | 64 | /** 65 | * 详情 66 | * 67 | * @param string $id 68 | * 69 | * @return mixed 70 | */ 71 | public function actionView($id) 72 | { 73 | $model = $this->auth_item_model->findModel($id, $this->type); 74 | if ( !$model) { 75 | return false; 76 | } 77 | 78 | return ArrayHelper::toArray($model->_item); 79 | } 80 | 81 | /** 82 | * 权限 | 角色 添加 83 | * 84 | * @return array|bool|\wind\rest\models\AuthItem 85 | */ 86 | public function actionCreate() 87 | { 88 | $res = $this->auth_item_model->addPermission($this->type); 89 | Helper::invalidate(); 90 | if ( !$res) { 91 | RbacHelper::error(); 92 | } 93 | if ($this->type == 1) { 94 | return ArrayHelper::toArray($res['_item']); 95 | } 96 | 97 | return $this->auth_item_model->getItems(); 98 | } 99 | 100 | /** 101 | * 修改 权限|角色 102 | * 103 | * @param $id 104 | * 105 | * @return array 106 | */ 107 | public function actionUpdate($id) 108 | { 109 | $this->auth_item_model->updatePermission($id, $this->type); 110 | Helper::invalidate(); 111 | if ($this->type == 1) { 112 | $res = $this->auth_item_model->findModel($id, $this->type); 113 | 114 | return ArrayHelper::toArray($res['_item']); 115 | } 116 | 117 | return $this->auth_item_model->getItems(); 118 | } 119 | 120 | /** 121 | * 删除权限 122 | * 123 | * @param $id 124 | * 125 | * @return array|bool 126 | */ 127 | public function actionDelete($id) 128 | { 129 | if ( !$this->auth_item_model->deletePermission($id, $this->type)) { 130 | return false; 131 | } 132 | Helper::invalidate(); 133 | 134 | return $this->auth_item_model->getItems(); 135 | } 136 | 137 | /** 138 | * 对于某个权限添加路由(左边到右边) 139 | * 140 | * @param string $id 141 | * 142 | * @return array 143 | */ 144 | public function actionAssign($id) 145 | { 146 | $this->auth_item_model->assignItem($id, $this->type, 'add'); 147 | 148 | return true; 149 | } 150 | 151 | /** 152 | * 对于某个权限删除路由(左边到右边) 153 | * 154 | * @param $id 155 | * 156 | * @return array 157 | */ 158 | public function actionRemove($id) 159 | { 160 | $this->auth_item_model->assignItem($id, $this->type, 'remove'); 161 | 162 | return true; 163 | } 164 | 165 | /** 166 | * @inheritdoc 167 | */ 168 | public function getViewPath() 169 | { 170 | return $this->module->getViewPath() . DIRECTORY_SEPARATOR . 'item'; 171 | } 172 | 173 | /** 174 | * Label use in view 175 | * 176 | * @throws NotSupportedException 177 | */ 178 | public function labels() 179 | { 180 | throw new NotSupportedException(get_class($this) . ' does not support labels().'); 181 | } 182 | 183 | /** 184 | * 可分配列表 185 | * 186 | * @param $id 187 | * 188 | * @return array|bool 189 | */ 190 | public function actionAssignList($id) 191 | { 192 | $model = $this->auth_item_model->findModel($id, $this->type); 193 | Yii::$app->getResponse()->format = 'json'; 194 | 195 | if ( !$model) { 196 | return false; 197 | } 198 | 199 | return $model->getItemsList(); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /components/MenuHelper.php: -------------------------------------------------------------------------------- 1 | MenuHelper::getAssignedMenu(Yii::$app->user->id) 19 | * ]); 20 | * ``` 21 | * 22 | * To reformat returned, provide callback to method. 23 | * 24 | * ``` 25 | * $callback = function ($menu) { 26 | * $data = eval($menu['data']); 27 | * return [ 28 | * 'label' => $menu['name'], 29 | * 'url' => [$menu['route']], 30 | * 'options' => $data, 31 | * 'items' => $menu['children'] 32 | * ] 33 | * ] 34 | * } 35 | * 36 | * $items = MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback, $client); 37 | * ``` 38 | * 39 | * @since 1.0 40 | */ 41 | class MenuHelper 42 | { 43 | 44 | /** 45 | * Use to get assigned menu of user. 46 | * 47 | * @param mixed $userId 48 | * @param integer $root 49 | * @param \Closure $callback use to reformat output. 50 | * callback should have format like 51 | * 52 | * ``` 53 | * function ($menu) { 54 | * return [ 55 | * 'label' => $menu['name'], 56 | * 'url' => [$menu['route']], 57 | * 'options' => $data, 58 | * 'items' => $menu['children'] 59 | * ] 60 | * ] 61 | * } 62 | * ``` 63 | * @param boolean $refresh 64 | * @param string $client 多应用情况下此参数,可作为区分不同应用的菜单,对应menu表中的`remark`字段(多应用-可作为应用类别使用) 65 | * 66 | * @return array 67 | */ 68 | public static function getAssignedMenu($userId, $root = null, $callback = null, $refresh = false, $client = null) 69 | { 70 | $config = Configs::instance(); 71 | 72 | /* @var $manager \yii\rbac\BaseManager */ 73 | $manager = Yii::$app->getAuthManager(); 74 | $menus = Menu::find()->asArray()->andFilterWhere(['remark' => $client])->indexBy('id')->all(); 75 | $key = [__METHOD__, $userId, $manager->defaultRoles]; 76 | $cache = $config->cache; 77 | 78 | if ($refresh || $cache === null || ($assigned = $cache->get($key)) === false) { 79 | $routes = $filter1 = $filter2 = []; 80 | if ($userId !== null) { 81 | foreach ($manager->getPermissionsByUser($userId) as $name => $value) { 82 | if ($name[0] === '/') { 83 | if (substr($name, -2) === '/*') { 84 | $name = substr($name, 0, -1); 85 | } 86 | $routes[] = $name; 87 | } 88 | } 89 | } 90 | foreach ($manager->defaultRoles as $role) { 91 | foreach ($manager->getPermissionsByRole($role) as $name => $value) { 92 | if ($name[0] === '/') { 93 | if (substr($name, -2) === '/*') { 94 | $name = substr($name, 0, -1); 95 | } 96 | $routes[] = $name; 97 | } 98 | } 99 | } 100 | $routes = array_unique($routes); 101 | sort($routes); 102 | $prefix = '\\'; 103 | foreach ($routes as $route) { 104 | if (strpos($route, $prefix) !== 0) { 105 | if (substr($route, -1) === '/') { 106 | $prefix = $route; 107 | $filter1[] = $route . '%'; 108 | } else { 109 | $filter2[] = $route; 110 | } 111 | } 112 | } 113 | $assigned = []; 114 | $query = Menu::find()->select(['id'])->andFilterWhere(['remark' => $client])->asArray(); 115 | if (count($filter2)) { 116 | $assigned = $query->where(['route' => $filter2])->column(); 117 | } 118 | if (count($filter1)) { 119 | $query->where('route like :filter'); 120 | foreach ($filter1 as $filter) { 121 | $assigned = array_merge($assigned, $query->params([':filter' => $filter])->column()); 122 | } 123 | } 124 | $assigned = static::requiredParent($assigned, $menus); 125 | if ($cache !== null) { 126 | $cache->set($key, $assigned, $config->cacheDuration, new TagDependency([ 127 | 'tags' => Configs::CACHE_TAG 128 | ])); 129 | } 130 | } 131 | 132 | $key = [__METHOD__, $assigned, $root]; 133 | if ($refresh || $callback !== null || $cache === null || (($result = $cache->get($key)) === false)) { 134 | $result = static::normalizeMenu($assigned, $menus, $callback, $root); 135 | if ($cache !== null && $callback === null) { 136 | $cache->set($key, $result, $config->cacheDuration, new TagDependency([ 137 | 'tags' => Configs::CACHE_TAG 138 | ])); 139 | } 140 | } 141 | 142 | return $result; 143 | } 144 | 145 | /** 146 | * Ensure all item menu has parent. 147 | * 148 | * @param array $assigned 149 | * @param array $menus 150 | * 151 | * @return array 152 | */ 153 | private static function requiredParent($assigned, &$menus) 154 | { 155 | $l = count($assigned); 156 | for ($i = 0; $i < $l; $i++) { 157 | $id = $assigned[$i]; 158 | $parent_id = $menus[$id]['parent']; 159 | if ($parent_id !== null && !in_array($parent_id, $assigned)) { 160 | $assigned[$l++] = $parent_id; 161 | } 162 | } 163 | 164 | return $assigned; 165 | } 166 | 167 | /** 168 | * Parse route 169 | * 170 | * @param string $route 171 | * 172 | * @return mixed 173 | */ 174 | public static function parseRoute($route) 175 | { 176 | if ( !empty($route)) { 177 | $url = []; 178 | $r = explode('&', $route); 179 | $url[0] = $r[0]; 180 | unset($r[0]); 181 | foreach ($r as $part) { 182 | $part = explode('=', $part); 183 | $url[$part[0]] = isset($part[1]) ? $part[1] : ''; 184 | } 185 | 186 | return $url; 187 | } 188 | 189 | return '#'; 190 | } 191 | 192 | /** 193 | * Normalize menu 194 | * 195 | * @param array $assigned 196 | * @param array $menus 197 | * @param Closure $callback 198 | * @param integer $parent 199 | * 200 | * @return array 201 | */ 202 | private static function normalizeMenu(&$assigned, &$menus, $callback, $parent = null) 203 | { 204 | $result = []; 205 | $order = []; 206 | foreach ($assigned as $id) { 207 | $menu = $menus[$id]; 208 | if ($menu['parent'] == $parent) { 209 | $menu['children'] = static::normalizeMenu($assigned, $menus, $callback, $id); 210 | if ($callback !== null) { 211 | $item = call_user_func($callback, $menu); 212 | } else { 213 | $item = [ 214 | 'label' => $menu['name'], 215 | 'url' => static::parseRoute($menu['route']), 216 | ]; 217 | if ($menu['children'] != []) { 218 | $item['items'] = $menu['children']; 219 | } 220 | } 221 | $result[] = $item; 222 | $order[] = $menu['order']; 223 | } 224 | } 225 | if ($result != []) { 226 | array_multisort($order, $result); 227 | } 228 | 229 | return $result; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /components/RouteRule.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0 13 | */ 14 | class RouteRule extends Rule 15 | { 16 | const RULE_NAME = 'route_rule'; 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | public $name = self::RULE_NAME; 22 | 23 | /** 24 | * @inheritdoc 25 | */ 26 | public function execute($user, $item, $params) 27 | { 28 | $routeParams = isset($item->data['params']) ? $item->data['params'] : []; 29 | foreach ($routeParams as $key => $value) { 30 | if (!array_key_exists($key, $params) || $params[$key] != $value) { 31 | return false; 32 | } 33 | } 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "windhoney/yii2-rest-rbac", 3 | "description": "RBAC Auth manager for Yii2 RESTful", 4 | "keywords": [ 5 | "yii", 6 | "admin", 7 | "auth", 8 | "rbac", 9 | "restful" 10 | ], 11 | "type": "yii2-extension", 12 | "license": "MIT", 13 | "support": { 14 | "issues": "https://github.com/windhoney/yii2-rest-rbac/issues", 15 | "source": "https://github.com/windhoney/yii2-rest-rbac" 16 | }, 17 | "authors": [ 18 | { 19 | "name": "windhoney", 20 | "email": "524415250@qq.com" 21 | } 22 | ], 23 | "require": { 24 | "yiisoft/yii2": "~2.0.7", 25 | "php": ">=7.0.0", 26 | "filsh/yii2-oauth2-server": "~2.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "wind\\rest\\": "" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /controllers/AssignmentController.php: -------------------------------------------------------------------------------- 1 | userClassName === null) { 33 | $this->userClassName = Yii::$app->getUser()->identityClass; 34 | $this->userClassName = $this->userClassName ?: 'rbac\models\User'; 35 | } 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function behaviors() 42 | { 43 | return [ 44 | 'verbs' => [ 45 | 'class' => VerbFilter::className(), 46 | 'actions' => [ 47 | 'assign' => ['post'], 48 | 'revoke' => ['post'], 49 | ], 50 | ], 51 | ]; 52 | } 53 | 54 | /** 55 | * 可分配列表 56 | * 57 | * @param $id 58 | * 59 | * @return array 60 | */ 61 | public function actionAssignList($id) 62 | { 63 | $model = new Assignment($id); 64 | Yii::$app->getResponse()->format = 'json'; 65 | 66 | return $model->getItemsList(); 67 | } 68 | 69 | /** 70 | * Lists all Assignment models. 71 | * 72 | * @return mixed 73 | */ 74 | public function actionIndex() 75 | { 76 | if ($this->searchClass === null) { 77 | $searchModel = new AssignmentSearch; 78 | $dataProvider = $searchModel->search(Yii::$app->getRequest()->getQueryParams(), $this->userClassName, 79 | $this->usernameField); 80 | } else { 81 | $class = $this->searchClass; 82 | $searchModel = new $class; 83 | $dataProvider = $searchModel->search(Yii::$app->getRequest()->getQueryParams()); 84 | } 85 | 86 | return $dataProvider; 87 | } 88 | 89 | /** 90 | * Displays a single Assignment model. 91 | * 92 | * @param integer $id 93 | * 94 | * @return mixed 95 | */ 96 | public function actionView($id) 97 | { 98 | $assignment_model = new Assignment($id); 99 | $res = $assignment_model->findModel($id, $this->userClassName); 100 | $data['id'] = $res->user['id']; 101 | $data['username'] = $res->user['username']; 102 | 103 | return $data; 104 | } 105 | 106 | /** 107 | * Assign items 108 | * 109 | * @param string $id 110 | * 111 | * @return bool 112 | */ 113 | public function actionAssign($id) 114 | { 115 | $items = Yii::$app->getRequest()->post(); 116 | $model = new Assignment($id); 117 | $success = $model->assign($items); 118 | // Yii::$app->getResponse()->format = 'json'; 119 | 120 | // return array_merge($model->getItems(), ['success' => $success]); 121 | return (bool)$success; 122 | } 123 | 124 | /** 125 | * Assign items 126 | * 127 | * @param string $id 128 | * 129 | * @return bool 130 | */ 131 | public function actionRevoke($id) 132 | { 133 | $items = Yii::$app->getRequest()->post(); 134 | $model = new Assignment($id); 135 | $success = $model->revoke($items); 136 | Yii::$app->getResponse()->format = 'json'; 137 | 138 | // return array_merge($model->getItems(), ['success' => $success]); 139 | return (bool)$success; 140 | } 141 | 142 | /** 143 | * Finds the Assignment model based on its primary key value. 144 | * If the model is not found, a 404 HTTP exception will be thrown. 145 | * 146 | * @param integer $id 147 | * 148 | * @return Assignment the loaded model 149 | * @throws NotFoundHttpException if the model cannot be found 150 | */ 151 | protected function findModel($id) 152 | { 153 | $class = $this->userClassName; 154 | if (($user = $class::findIdentity($id)) !== null) { 155 | return new Assignment($id, $user); 156 | } 157 | 158 | throw new NotFoundHttpException('The requested page does not exist.'); 159 | } 160 | 161 | /** 162 | * 批量分配角色到人 163 | * 164 | * @param array $id 165 | * 166 | * @return bool 167 | */ 168 | public function actionAssignBatch($id) 169 | { 170 | $users = $this->params; 171 | $model = new Assignment($id); 172 | $success = $model->assignBatch($users); 173 | 174 | return (bool)$success; 175 | } 176 | 177 | /** 178 | * 权限|角色 已分配人,未分配人 179 | * 180 | * @param $id 181 | * 182 | * @return array 183 | */ 184 | public function actionAssignUsers($id) 185 | { 186 | $model = new Assignment($id); 187 | 188 | return $model->assignUser(); 189 | } 190 | 191 | /** 192 | * 批量删除角色的人 193 | * 194 | * @param array $id 195 | * 196 | * @return bool 197 | */ 198 | public function actionRemoveUsers($id) 199 | { 200 | $users = $this->params; 201 | $model = new Assignment($id); 202 | $success = $model->assignRemoveUsers($users); 203 | 204 | return (bool)$success; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /controllers/AuthItemController.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'class' => VerbFilter::className(), 25 | 'actions' => [ 26 | 'delete' => ['post'], 27 | ], 28 | ], 29 | ]; 30 | } 31 | 32 | public function init() 33 | { 34 | parent::init(); 35 | $this->auth_item_model = new AuthItem(); 36 | } 37 | 38 | public function actionIndex() 39 | { 40 | $res = $this->auth_item_model->getItems(); 41 | 42 | return $res; 43 | } 44 | 45 | public function actionCreate() 46 | { 47 | $res = $this->auth_item_model->save(); 48 | 49 | return $res; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /controllers/GroupsController.php: -------------------------------------------------------------------------------- 1 | request->get('id'); 23 | $this->group_model = new AuthGroups($id); 24 | } 25 | 26 | /** 27 | * 可用店铺列表 28 | * 29 | * @return array|\yii\db\ActiveRecord[] 30 | */ 31 | public function actionIndex() 32 | { 33 | $result = $this->group_model->lists(); 34 | 35 | return $result; 36 | } 37 | 38 | /** 39 | * 分配添加 40 | * 41 | * @return bool 42 | */ 43 | public function actionAssign() 44 | { 45 | $result = $this->group_model->assign(); 46 | 47 | return $result; 48 | } 49 | 50 | /** 51 | * 分配删除 52 | * 53 | * @return bool 54 | */ 55 | public function actionRevoke() 56 | { 57 | $result = $this->group_model->revoke(); 58 | 59 | return $result; 60 | } 61 | 62 | /** 63 | * 分配列表 64 | * 65 | * @return array 66 | */ 67 | public function actionAssignUser() 68 | { 69 | $result = $this->group_model->assignUser(); 70 | 71 | return $result; 72 | } 73 | 74 | /** 75 | * 添加|修改 76 | * 只能修改名称 77 | * 78 | * @return bool 79 | */ 80 | public function actionCreate() 81 | { 82 | $group_id = \Yii::$app->request->post('group_id'); 83 | $group_name = \Yii::$app->request->post('group_name'); 84 | 85 | return $this->group_model->create($group_id, $group_name); 86 | } 87 | 88 | /** 89 | * 停用|启用 90 | * 91 | * @return bool 92 | */ 93 | public function actionStatus() 94 | { 95 | $group_id = \Yii::$app->request->post('group_id'); 96 | $group_status = \Yii::$app->request->post('group_status'); 97 | 98 | return $this->group_model->status($group_id, $group_status); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /controllers/MenuController.php: -------------------------------------------------------------------------------- 1 | menu_model = new Menu(); 25 | } 26 | 27 | /** 28 | * 用户菜单 29 | * 30 | * @return array 31 | */ 32 | public function actionUserMenu() 33 | { 34 | $callback = function ($menu) { 35 | $data = json_decode($menu['data'], true); 36 | $items = $menu['children']; 37 | $return['label'] = $menu['name']; 38 | $return['url'] = $menu['route'] ? substr($menu['route'], 1) : ''; 39 | $return['icon'] = $data['icon'] ?? 'fa fa-circle-o'; 40 | $return['visible'] = $data['visible'] ?? true; 41 | $items && $return['items'] = $items; 42 | 43 | return $return; 44 | }; 45 | $refresh = Yii::$app->request->get('refresh', false); 46 | $result = MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback, $refresh, Yii::$app->request->get('client')); 47 | 48 | return $result; 49 | } 50 | 51 | /** 52 | * 所有菜单列表 53 | * 54 | * @return mixed 55 | */ 56 | public function actionIndex() 57 | { 58 | $res = $this->menu_model->getMenuSource(); 59 | $is_tree = Yii::$app->request->get('is_tree'); 60 | if ($is_tree) { 61 | return Helper::makeTree($res, 'name', 'parent_name', 'child', null); 62 | } 63 | 64 | return $res; 65 | } 66 | 67 | /** 68 | * 菜单详情 69 | * 70 | * @param integer $id 71 | * 72 | * @return mixed 73 | */ 74 | public function actionView($id) 75 | { 76 | $res = $this->menu_model->findModel($id); 77 | $parent_name = $res->parent_name; 78 | $description = $res->description; 79 | $res = ArrayHelper::toArray($res); 80 | $res['parent_name'] = $parent_name; 81 | $res['description'] = $description; 82 | 83 | return $res; 84 | } 85 | 86 | /** 87 | * 添加菜单 88 | * 89 | * @return mixed 90 | */ 91 | public function actionCreate() 92 | { 93 | $result = $this->menu_model->create(); 94 | 95 | return $this->menu_model->findModel($result['id']); 96 | } 97 | 98 | /** 99 | * 更新 100 | * 101 | * @param integer $id 102 | * 103 | * @return mixed 104 | */ 105 | public function actionUpdate($id) 106 | { 107 | $result = $this->menu_model->updateMenu($id); 108 | 109 | return $this->menu_model->findModel($result['id']); 110 | } 111 | 112 | /** 113 | * 删除 114 | * 115 | * @param $id 116 | * 117 | * @return array 118 | */ 119 | public function actionDelete($id) 120 | { 121 | $this->menu_model->deleteMenu($id); 122 | Helper::invalidate(); 123 | 124 | return $this->menu_model->getMenuSource(); 125 | } 126 | } -------------------------------------------------------------------------------- /controllers/PermissionController.php: -------------------------------------------------------------------------------- 1 | 'Permission', 22 | 'Items' => 'Permissions', 23 | ]; 24 | } 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public function getType() 30 | { 31 | return Item::TYPE_PERMISSION; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /controllers/RoleController.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0 13 | */ 14 | class RoleController extends ItemController 15 | { 16 | /** 17 | * @inheritdoc 18 | */ 19 | public function labels() 20 | { 21 | return[ 22 | 'Item' => 'Role', 23 | 'Items' => 'Roles', 24 | ]; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function getType() 31 | { 32 | return Item::TYPE_ROLE; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /controllers/RouteController.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0 16 | */ 17 | class RouteController extends ApiController 18 | { 19 | 20 | public function behaviors() 21 | { 22 | return ArrayHelper::merge(parent::behaviors(), [ 23 | 'verbs' => [ 24 | 'class' => VerbFilter::className(), 25 | 'actions' => [ 26 | 'create' => ['post'], 27 | 'assign' => ['post'], 28 | 'remove' => ['post'], 29 | ], 30 | ], 31 | ]); 32 | } 33 | 34 | /** 35 | * 已分配的路由列表 36 | * 37 | * @return array 38 | */ 39 | public function actionIndex() 40 | { 41 | $model = new Route(); 42 | $result = $model->getRoutes(); 43 | 44 | return $result['assigned']; 45 | } 46 | 47 | /** 48 | * 可用路由列表 49 | * 50 | * @return array 51 | */ 52 | public function actionAll() 53 | { 54 | $model = new Route(); 55 | $result = $model->getRoutes(); 56 | 57 | return $result['avaliable']; 58 | } 59 | 60 | /** 61 | * 添加路由 62 | * 63 | * @return mixed 64 | */ 65 | public function actionCreate() 66 | { 67 | $routes = Yii::$app->getRequest()->post(); 68 | $model = new Route(); 69 | $model->addNew($routes); 70 | 71 | return $model->getRoutes()['assigned']; 72 | } 73 | 74 | /** 75 | * 删除路由 76 | * 77 | * @return array 78 | */ 79 | public function actionRemove() 80 | { 81 | $routes = Yii::$app->getRequest()->post(); 82 | $model = new Route(); 83 | $model->remove($routes); 84 | Yii::$app->getResponse()->format = 'json'; 85 | 86 | return $model->getRoutes()['assigned']; 87 | } 88 | 89 | /** 90 | * 父级路由列表 91 | * 92 | * @return array 93 | */ 94 | public function actionParent() 95 | { 96 | $model = new Route(); 97 | $result = $model->parentList(); 98 | $result = array_filter($result); 99 | sort($result); 100 | 101 | return $result; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /controllers/RuleController.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 1.0 17 | */ 18 | class RuleController extends ApiController 19 | { 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | public function behaviors() 25 | { 26 | return [ 27 | 'verbs' => [ 28 | 'class' => VerbFilter::className(), 29 | 'actions' => [ 30 | 'delete' => ['post'], 31 | 'assign' => ['post', 'get'], 32 | 'remove' => ['post'], 33 | ], 34 | ], 35 | ]; 36 | } 37 | 38 | /** 39 | * Creates a new AuthItems model. 40 | * If creation is successful, the browser will be redirected to the 'view' page. 41 | * 42 | * @return mixed 43 | */ 44 | public function actionCreate() 45 | { 46 | $model = new BizRule(null); 47 | if ($model->load(Yii::$app->request->post(), '') && $model->save()) { 48 | Helper::invalidate(); 49 | 50 | return true; 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | /** 57 | * Updates an existing AuthItem model. 58 | * If update is successful, the browser will be redirected to the 'view' page. 59 | * 60 | * @param string $id 61 | * 62 | * @return mixed 63 | */ 64 | public function actionUpdate() 65 | { 66 | $delete_result = $this->actionDelete(); 67 | if ($delete_result == false) { 68 | return $delete_result; 69 | } 70 | $create_result = $this->actionCreate(); 71 | 72 | return $create_result; 73 | } 74 | 75 | /** 76 | * Deletes an existing AuthItem model. 77 | * If deletion is successful, the browser will be redirected to the 'index' page. 78 | * 79 | * @return bool 80 | */ 81 | public function actionDelete() 82 | { 83 | $name = Yii::$app->request->getBodyParam("name"); 84 | $model = $this->findModel($name); 85 | 86 | if ($model != false) { 87 | Yii::$app->authManager->remove($model->item); 88 | Helper::invalidate(); 89 | 90 | return true; 91 | } 92 | 93 | return false; 94 | } 95 | 96 | /** 97 | * Finds the AuthItem model based on its primary key value. 98 | * If the model is not found, a 404 HTTP exception will be thrown. 99 | * 100 | * @param $id 101 | * 102 | * @return false|BizRule 103 | */ 104 | protected function findModel($id) 105 | { 106 | $item = Yii::$app->authManager->getRule($id); 107 | if ($item) { 108 | return new BizRule($item); 109 | } else { 110 | //log error 111 | return false; 112 | } 113 | } 114 | 115 | /** 116 | * @return array 117 | */ 118 | public function actionGetRules() 119 | { 120 | $rules = Yii::$app->getAuthManager()->getRules(); 121 | $result_rules = []; 122 | foreach ($rules as $rule_name => $rule_obj) { 123 | $r_obj["rule_name"] = $rule_name; 124 | $r_obj["rule_class"] = $rule_obj->className(); 125 | $result_rules[] = $r_obj; 126 | } 127 | 128 | return $result_rules; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | search(Yii::$app->request->queryParams); 35 | 36 | return $result; 37 | } 38 | 39 | /** 40 | * 用户详情 41 | * 42 | * @param $id 43 | * 44 | * @return \wind\rest\models\User 45 | */ 46 | public function actionView($id) 47 | { 48 | $select = [ 49 | "id", 50 | "username", 51 | "realname", 52 | "email", 53 | "status", 54 | "created_at", 55 | "updated_at" 56 | ]; 57 | $result = $this->findModel($id, $select); 58 | $result->created_at = date('Y年m月d日', $result->created_at); 59 | $result->updated_at = date('Y年m月d日', $result->updated_at); 60 | 61 | return $result; 62 | } 63 | 64 | /** 65 | * Deletes an existing User model. 66 | * If deletion is successful, the browser will be redirected to the 'index' page. 67 | * 68 | * @param integer $id 69 | * 70 | * @return mixed 71 | */ 72 | public function actionDelete($id) 73 | { 74 | $this->findModel($id)->delete(); 75 | 76 | return $this->redirect(['index']); 77 | } 78 | 79 | /** 80 | * Login 81 | * 82 | * @return string 83 | */ 84 | public function actionLogin() 85 | { 86 | if ( !Yii::$app->getUser()->isGuest) { 87 | return $this->goHome(); 88 | } 89 | 90 | $model = new Login(); 91 | if ($model->load(Yii::$app->getRequest()->post()) && $model->login()) { 92 | return $this->goBack(); 93 | } else { 94 | return $this->render('login', [ 95 | 'model' => $model, 96 | ]); 97 | } 98 | } 99 | 100 | /** 101 | * Logout 102 | * 103 | * @return string 104 | */ 105 | public function actionLogout() 106 | { 107 | Yii::$app->getUser()->logout(); 108 | 109 | return $this->goHome(); 110 | } 111 | 112 | /** 113 | * Signup new user 114 | * 115 | * @return string 116 | */ 117 | public function actionSignup() 118 | { 119 | $model = new Signup(); 120 | if ($model->load(Yii::$app->getRequest()->post())) { 121 | if ($user = $model->signup()) { 122 | return $this->goHome(); 123 | } 124 | } 125 | 126 | return $this->render('signup', [ 127 | 'model' => $model, 128 | ]); 129 | } 130 | 131 | /** 132 | * Request reset password 133 | * 134 | * @return string 135 | */ 136 | public function actionRequestPasswordReset() 137 | { 138 | $model = new PasswordResetRequest(); 139 | if ($model->load(Yii::$app->getRequest()->post()) && $model->validate()) { 140 | if ($model->sendEmail()) { 141 | Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); 142 | 143 | return $this->goHome(); 144 | } else { 145 | Yii::$app->getSession()->setFlash('error', 146 | 'Sorry, we are unable to reset password for email provided.'); 147 | } 148 | } 149 | 150 | return $this->render('requestPasswordResetToken', [ 151 | 'model' => $model, 152 | ]); 153 | } 154 | 155 | /** 156 | * Reset password 157 | * 158 | * @return string 159 | */ 160 | public function actionResetPassword($token) 161 | { 162 | try { 163 | $model = new ResetPassword($token); 164 | } catch (InvalidParamException $e) { 165 | throw new BadRequestHttpException($e->getMessage()); 166 | } 167 | 168 | if ($model->load(Yii::$app->getRequest()->post()) && $model->validate() && $model->resetPassword()) { 169 | Yii::$app->getSession()->setFlash('success', 'New password was saved.'); 170 | 171 | return $this->goHome(); 172 | } 173 | 174 | return $this->render('resetPassword', [ 175 | 'model' => $model, 176 | ]); 177 | } 178 | 179 | /** 180 | * Reset password 181 | * 182 | * @return string 183 | */ 184 | public function actionChangePassword() 185 | { 186 | $model = new ChangePassword(); 187 | if ($model->load(Yii::$app->getRequest()->post()) && $model->change()) { 188 | return $this->goHome(); 189 | } 190 | 191 | return $this->render('change-password', [ 192 | 'model' => $model, 193 | ]); 194 | } 195 | 196 | /** 197 | * 修改用户状态 198 | * 199 | * @param $id 200 | * 201 | * @return bool 202 | */ 203 | public function actionActivate($id) 204 | { 205 | /* @var $user User */ 206 | $user = $this->findModel($id); 207 | if ($user->status == User::STATUS_INACTIVE) { 208 | $user->status = User::STATUS_ACTIVE; 209 | if ($user->save()) { 210 | return true; 211 | // return $this->goHome(); 212 | } else { 213 | $errors = $user->firstErrors; 214 | 215 | return false; 216 | // throw new UserException(reset($errors)); 217 | } 218 | } 219 | 220 | return true; 221 | // return $this->goHome(); 222 | } 223 | 224 | /** 225 | * Finds the User model based on its primary key value. 226 | * If the model is not found, a 404 HTTP exception will be thrown. 227 | * 228 | * @param integer $id 229 | * 230 | * @return User the loaded model 231 | * @throws NotFoundHttpException if the model cannot be found 232 | */ 233 | protected function findModel($id, $select = ['*']) 234 | { 235 | if (($model = User::find()->andWhere(['id' => $id])->select($select)->one()) !== null) { 236 | return $model; 237 | } else { 238 | return false; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /controllers/base/ApiController.php: -------------------------------------------------------------------------------- 1 | user_id = \Yii::$app->user->id; 31 | $this->getRequestParam(); 32 | } 33 | 34 | public function behaviors() 35 | { 36 | return ArrayHelper::merge(parent::behaviors(), [ 37 | 'authenticator' => [ 38 | 'class' => CompositeAuth::className(), 39 | 'authMethods' => [ 40 | ['class' => QueryParamAuth::className(), 'tokenParam' => 'access_token'], 41 | ] 42 | ] 43 | ]); 44 | } 45 | 46 | public function actions() 47 | { 48 | $actions = parent::actions(); 49 | // 注销系统自带的实现方法 50 | unset($actions['index']); 51 | unset($actions['create']); 52 | unset($actions['update']); 53 | unset($actions['delete']); 54 | unset($actions['view']); 55 | 56 | return $actions; 57 | } 58 | 59 | /** 60 | * 接收请求参数 61 | */ 62 | public function getRequestParam() 63 | { 64 | if (\Yii::$app->request->isPost) { 65 | $data = \Yii::$app->request->getRawBody(); 66 | $post = json_decode($data, true); 67 | if ( !$post && $data) { 68 | RbacHelper::error(400, '数据格式不正确'); 69 | } else { 70 | $this->params = $post; 71 | } 72 | } else { 73 | $this->params = \Yii::$app->request->queryParams; 74 | } 75 | } 76 | 77 | /** 78 | * @inheritdoc 79 | */ 80 | protected function verbs() 81 | { 82 | return [ 83 | 'index' => ['GET', 'HEAD', 'PUT', 'POST'], 84 | ]; 85 | } 86 | 87 | /** 88 | * @inheritdoc 89 | */ 90 | public function afterAction($action, $result) 91 | { 92 | \Yii::$app->response->format = "json"; 93 | $result = parent::afterAction($action, $result); 94 | $data['code'] = isset($result['code']) ? $result['code'] : 200; 95 | $data['message'] = isset($result['message']) ? $result['message'] : '操作成功'; 96 | if ($result === null) { 97 | $result = []; 98 | } 99 | if ($data['code'] == 200 && (is_array($result))) { 100 | $data['data'] = $result; 101 | } 102 | if ($result === false) { 103 | $data['code'] = 400; 104 | $data['message'] = '操作失败'; 105 | } 106 | 107 | return $this->serializeData($data); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /example/auth_item_sql: -------------------------------------------------------------------------------- 1 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/assign', 2, '接口-人员权限分配或者删除', NULL, '权限控制', '', 1526377735, 1526377269); 2 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/assign-batch', 2, '接口-角色分配用户(添加)', NULL, '权限控制', '', 1526377735, 1526377269); 3 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/assign-list', 2, '接口-人员权限分配状态', NULL, '权限控制', '', 1526377735, 1526377269); 4 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/assign-users', 2, '接口-角色分配用户页面', NULL, '权限控制', '', 1526377735, 1526377269); 5 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/remove-users', 2, '接口-角色分配用户(删除)', NULL, '权限控制', '', 1526377735, 1526377269); 6 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/assignment/revoke', 2, '接口-人员权限删除', NULL, '权限控制', '', 1526377735, 1526377269); 7 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/groups/assign', 2, '分组-添加用户', NULL, '权限控制', '', 1526377735, 1526377269); 8 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/groups/assign-user', 2, '分组下用户列表', NULL, '权限控制', '', 1526377735, 1526377269); 9 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/groups/index', 2, '店铺-列表', NULL, '权限控制', '', 1526377735, 1526377269); 10 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/groups/revoke', 2, '分组-删除用户', NULL, '权限控制', '', 1526377735, 1526377269); 11 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/create', 2, '接口-新增菜单接口', NULL, '权限控制', '', 1526377735, 1526377269); 12 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/delete', 2, '接口-删除菜单接口', NULL, '权限控制', '', 1526377735, 1526377269); 13 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/index', 2, '接口-菜单接口', NULL, '权限控制', '', 1526377735, 1526377269); 14 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/update', 2, '接口-菜单更新接口', NULL, '权限控制', '', 1526377735, 1526377269); 15 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/menu/view', 2, '接口-菜单弹出框的接口', NULL, '权限控制', '', 1526377735, 1526377269); 16 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/assign', 2, '接口-分配权限', NULL, '权限控制', '', 1526377735, 1526377269); 17 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/assign-list', 2, '接口-分配权限列表', NULL, '权限控制', '', 1526377735, 1526377269); 18 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/create', 2, '接口-权限的添加接口', NULL, '权限控制', '', 1526377735, 1526377269); 19 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/delete', 2, '接口-删除权限', NULL, '权限控制', '', 1526377735, 1526377269); 20 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/index', 2, '接口-权限页面', NULL, '权限控制', '', 1526377735, 1526377269); 21 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/remove', 2, '接口-删除分配权限', NULL, '权限控制', '', 1526377735, 1526377269); 22 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/update', 2, '接口-更新权限接口', NULL, '权限控制', '', 1526377735, 1526377269); 23 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/permission/view', 2, '接口-权限分配页面', NULL, '权限控制', '', 1526377735, 1526377269); 24 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/assign', 2, '接口-分配角色接口', NULL, '权限控制', '', 1526377735, 1526377269); 25 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/assign-list', 2, '接口-分配角色列表', NULL, '权限控制', '', 1526377735, 1526377269); 26 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/create', 2, '接口-角色创建的接口', NULL, '权限控制', '', 1526377735, 1526377269); 27 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/delete', 2, '接口-角色删除', NULL, '权限控制', '', 1526377735, 1526377269); 28 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/index', 2, '接口-角色接口', NULL, '权限控制', '', 1526377735, 1526377269); 29 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/remove', 2, '接口-删除分配权限接口', NULL, '权限控制', '', 1526377735, 1526377269); 30 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/update', 2, '接口-更新权限接口', NULL, '权限控制', '', 1526377735, 1526377269); 31 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/role/view', 2, '接口-编辑权限弹出框接口', NULL, '权限控制', '', 1526377735, 1526377269); 32 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/route/create', 2, '接口-路由接口添加', NULL, '权限控制', '', 1526377735, 1526377269); 33 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/route/index', 2, '接口-路由接口', NULL, '权限控制', '', 1526377735, 1526377269); 34 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/route/parent', 2, '接口-父级路由名称', NULL, '权限控制', '', 1526377735, 1526377269); 35 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/route/remove', 2, '接口-路由接口删除', NULL, '权限控制', '', 1526377735, 1526377269); 36 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/rule/create', 2, '接口-新建规则接口', NULL, '权限控制', '', 1526377735, 1526377269); 37 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/rule/delete', 2, '接口-删除规则接口', NULL, '权限控制', '', 1526377735, 1526377269); 38 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/rule/get-rules', 2, '接口-规则添加接口', NULL, '权限控制', '', 1526377735, 1526377269); 39 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/rule/update', 2, '接口-修改规则接口', NULL, '权限控制', '', 1526377735, 1526377269); 40 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/user/index', 2, '接口-获取所有人员', NULL, '权限控制', '', 1526377735, 1526377269); 41 | INSERT INTO `auth_item`(`name`, `type`, `description`, `rule_name`, `parent_name`, `data`, `created_at`, `updated_at`) VALUES ('/rbac/user/view', 2, '接口-人员权限分配列表', NULL, '权限控制', '', 1526377735, 1526377269); 42 | -------------------------------------------------------------------------------- /example/rbac_route.php: -------------------------------------------------------------------------------- 1 | 'yii\rest\UrlRule', 18 | 'controller' => ['rbac/permission'], 19 | 'extraPatterns' => [ 20 | 'GET view' => 'view', 21 | 'DELETE delete' => 'delete', 22 | 'POST update' => 'update', 23 | 'POST assign' => 'assign', 24 | 'POST remove' => 'remove', 25 | 'GET assign-list' => 'assign-list', 26 | ] 27 | ], 28 | //菜单 29 | [ 30 | 'class' => 'yii\rest\UrlRule', 31 | 'controller' => ['rbac/menu'], 32 | 'extraPatterns' => [ 33 | 'GET parent' => 'parent', 34 | 'POST create' => 'create', 35 | 'POST update' => 'update', 36 | 'GET user' => 'user-menu' 37 | ] 38 | ], 39 | //路由 40 | [ 41 | 'class' => 'yii\rest\UrlRule', 42 | 'controller' => ['rbac/route'], 43 | 'extraPatterns' => [ 44 | 'POST remove' => 'remove', 45 | 'GET all' => 'all', 46 | 'GET parent' => 'parent', 47 | ] 48 | ], 49 | //角色 50 | [ 51 | 'class' => 'yii\rest\UrlRule', 52 | 'controller' => ['rbac/role'], 53 | 'extraPatterns' => [ 54 | 'GET view' => 'view', 55 | 'DELETE delete' => 'delete', 56 | 'POST update' => 'update', 57 | 'POST assign' => 'assign', 58 | 'GET assign-list' => 'assign-list', 59 | 'POST remove' => 'remove', 60 | ] 61 | ], 62 | //分配 63 | [ 64 | 'class' => 'yii\rest\UrlRule', 65 | 'controller' => ['rbac/assignment'], 66 | 'extraPatterns' => [ 67 | 'GET view' => 'view', 68 | 'POST assign' => 'assign', 69 | 'POST revoke' => 'revoke', 70 | 'GET assign-list' => 'assign-list', 71 | 'POST remove' => 'remove', 72 | 'POST assign-batch' => 'assign-batch', 73 | 'POST assign-remove' => 'remove-users', 74 | 'GET assign-users' => 'assign-users', 75 | ] 76 | ], 77 | //用户 78 | [ 79 | 'class' => 'yii\rest\UrlRule', 80 | 'controller' => ['rbac/user'], 81 | 'extraPatterns' => [ 82 | 'GET view' => 'view', 83 | 'POST activate' => 'activate', 84 | ] 85 | ], 86 | //规则 87 | [ 88 | 'class' => 'yii\rest\UrlRule', 89 | 'controller' => ['rbac/rule'], 90 | 'extraPatterns' => [ 91 | 'GET index' => 'get-rules', 92 | 'POST create' => 'create', 93 | 'POST delete' => 'delete', 94 | 'POST update' => 'update', 95 | ] 96 | ], 97 | //分组 98 | [ 99 | 'class' => 'yii\rest\UrlRule', 100 | 'controller' => ['rbac/groups'], 101 | 'extraPatterns' => [ 102 | 'POST assign' => 'assign', 103 | 'POST revoke' => 'revoke', 104 | 'GET assign-user' => 'assign-user', 105 | 'POST status' => 'status', 106 | ] 107 | ] 108 | ]; 109 | 110 | return $rules; 111 | -------------------------------------------------------------------------------- /helper/RbacHelper.php: -------------------------------------------------------------------------------- 1 | logFile = \Yii::$app->getRuntimePath() . '/logs/' . $file_name . '.log'; 90 | $log->messages[] = [$message, 1, $action, $time]; 91 | $log->export(); 92 | } 93 | 94 | /** 95 | * 添加路由配置 96 | * 97 | * @param $dir 98 | * @param $main 99 | * 100 | * @return mixed 101 | */ 102 | public static function addRoute($dir, $main) 103 | { 104 | $file = scandir($dir); 105 | $file = array_filter($file, function ($k) { 106 | return strpos($k, '.php'); 107 | }); 108 | $route_arr = []; 109 | foreach ($file as $item) { 110 | $route_arr[] = require($dir . '/' . $item); 111 | } 112 | foreach ($route_arr as $route) { 113 | if ( !empty($route)) { 114 | foreach ($route as $v) { 115 | array_push($main['components']['urlManager']['rules'], $v); 116 | } 117 | } 118 | } 119 | 120 | return $main; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /jetbrains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windhoney/yii2-rest-rbac/f04e4d9f99cbe7710e687b337b906615e46775d9/jetbrains.png -------------------------------------------------------------------------------- /migrations/m140602_111327_create_menu_table.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0 10 | */ 11 | class m140602_111327_create_menu_table extends \yii\db\Migration 12 | { 13 | 14 | /** 15 | * @inheritdoc 16 | */ 17 | public function up() 18 | { 19 | $menuTable = Configs::instance()->menuTable; 20 | $tableOptions = null; 21 | if ($this->db->driverName === 'mysql') { 22 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; 23 | } 24 | 25 | $this->createTable($menuTable, [ 26 | 'id' => $this->primaryKey(), 27 | 'name' => $this->string(128)->notNull(), 28 | 'parent' => $this->integer(), 29 | 'route' => $this->string(), 30 | 'remark' => $this->string(), 31 | 'order' => $this->integer(), 32 | 'data' => $this->binary(), 33 | "FOREIGN KEY ([[parent]]) REFERENCES {$menuTable}([[id]]) ON DELETE SET NULL ON UPDATE CASCADE", 34 | ], $tableOptions); 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | */ 40 | public function down() 41 | { 42 | $this->dropTable(Configs::instance()->menuTable); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /migrations/m160312_050000_create_user.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 13 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci 14 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 15 | } 16 | 17 | $userTable = Configs::instance()->userTable; 18 | 19 | // Check if the table exists 20 | if ($this->db->schema->getTableSchema($userTable, true) === null) { 21 | $this->createTable($userTable, [ 22 | 'id' => $this->primaryKey(), 23 | 'username' => $this->string(32)->notNull(), 24 | 'realname' => $this->string(100)->notNull(), 25 | 'auth_key' => $this->string(32)->notNull(), 26 | 'password_hash' => $this->string()->notNull(), 27 | 'password_reset_token' => $this->string(), 28 | 'email' => $this->string()->notNull(), 29 | 'status' => $this->smallInteger()->notNull()->defaultValue(10), 30 | 'created_at' => $this->integer()->notNull(), 31 | 'updated_at' => $this->integer()->notNull(), 32 | ], $tableOptions); 33 | } 34 | } 35 | 36 | public function down() 37 | { 38 | $userTable = Configs::instance()->userTable; 39 | if ($this->db->schema->getTableSchema($userTable, true) !== null) { 40 | $this->dropTable($userTable); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /migrations/schema-mssql.sql: -------------------------------------------------------------------------------- 1 | /** 2 | * Database schema required by yii2-admin. 3 | * 4 | * @author Misbahul D Munir 5 | * @since 2.5 6 | */ 7 | 8 | drop table if exists [menu]; 9 | drop table if exists [user]; 10 | 11 | create table [menu] 12 | ( 13 | [id] int IDENTITY PRIMARY KEY, 14 | [name] varchar(128), 15 | [parent] int(11), 16 | [route] varchar(256), 17 | [order] int(11), 18 | [data] text, 19 | foreign key (parent) references [menu]([id]) ON DELETE SET NULL ON UPDATE CASCADE 20 | ); 21 | 22 | create table [user] 23 | ( 24 | [id] int IDENTITY PRIMARY KEY, 25 | [username] varchar(32) NOT NULL, 26 | [auth_key] varchar(32) NOT NULL, 27 | [password_hash] varchar(256) NOT NULL, 28 | [password_reset_token] varchar(256), 29 | [email] varchar(256) NOT NULL, 30 | [status] integer not null default 10, 31 | [created_at] integer not null, 32 | [updated_at] integer not null 33 | ); 34 | -------------------------------------------------------------------------------- /migrations/schema-mysql.sql: -------------------------------------------------------------------------------- 1 | /** 2 | * Database schema required by yii2-admin. 3 | * 4 | * @since 2.5 5 | */ 6 | 7 | drop table if exists `menu`; 8 | drop table if exists `user` cascade; 9 | 10 | create table `menu` 11 | ( 12 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 13 | `name` varchar(128), 14 | `parent` int(11), 15 | `route` varchar(256), 16 | `order` int(11), 17 | `data` blob, 18 | foreign key (`parent`) references `menu`(`id`) ON DELETE SET NULL ON UPDATE CASCADE 19 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 20 | 21 | create table `user` 22 | ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 24 | `username` varchar(32) NOT NULL, 25 | `auth_key` varchar(32) NOT NULL, 26 | `password_hash` varchar(256) NOT NULL, 27 | `password_reset_token` varchar(256), 28 | `email` varchar(256) NOT NULL, 29 | `status` integer not null default 10, 30 | `created_at` integer not null, 31 | `updated_at` integer not null 32 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 33 | -------------------------------------------------------------------------------- /migrations/schema-oci.sql: -------------------------------------------------------------------------------- 1 | /** 2 | * Database schema required by yii2-admin. 3 | * 4 | * @author Misbahul D Munir 5 | * @since 2.5 6 | */ 7 | 8 | drop table if exists "menu"; 9 | drop table if exists "user"; 10 | 11 | create table "menu" 12 | ( 13 | "id" NUMBER(10) NOT NULL PRIMARY KEY, 14 | "name" varchar(128), 15 | "parent" number(10), 16 | "route" varchar(256), 17 | "order" number(10), 18 | "data" BYTEA, 19 | foreign key (parent) references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE 20 | ); 21 | 22 | create table "user" 23 | ( 24 | "id" NUMBER(10) NOT NULL PRIMARY KEY, 25 | "username" varchar(32) NOT NULL, 26 | "auth_key" varchar(32) NOT NULL, 27 | "password_hash" varchar(256) NOT NULL, 28 | "password_reset_token" varchar(256), 29 | "email" varchar(256) NOT NULL, 30 | "status" integer not null default 10, 31 | "created_at" number(10) not null, 32 | "updated_at" number(10) not null 33 | ); 34 | -------------------------------------------------------------------------------- /migrations/schema-pgsql.sql: -------------------------------------------------------------------------------- 1 | /** 2 | * Database schema required by yii2-admin. 3 | * 4 | * @author Misbahul D Munir 5 | * @since 2.5 6 | */ 7 | 8 | drop table if exists "menu"; 9 | drop table if exists "user"; 10 | 11 | create table "menu" 12 | ( 13 | "id" serial NOT NULL PRIMARY KEY, 14 | "name" varchar(128), 15 | "parent" integer, 16 | "route" varchar(256), 17 | "order" integer, 18 | "data" bytea, 19 | foreign key ("parent") references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE 20 | ); 21 | 22 | create table "user" 23 | ( 24 | "id" serial NOT NULL PRIMARY KEY, 25 | "username" varchar(32) NOT NULL, 26 | "auth_key" varchar(32) NOT NULL, 27 | "password_hash" varchar(256) NOT NULL, 28 | "password_reset_token" varchar(256), 29 | "email" varchar(256) NOT NULL, 30 | "status" integer not null default 10, 31 | "created_at" integer not null, 32 | "updated_at" integer not null 33 | ); 34 | -------------------------------------------------------------------------------- /migrations/schema-sqlite.sql: -------------------------------------------------------------------------------- 1 | /** 2 | * Database schema required by yii2-admin. 3 | * 4 | * @author Misbahul D Munir 5 | * @since 2.5 6 | */ 7 | 8 | drop table if exists "menu"; 9 | drop table if exists "user"; 10 | 11 | create table "menu" 12 | ( 13 | "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, 14 | "name" varchar(128), 15 | "parent" int(11), 16 | "route" varchar(256), 17 | "order" int(11), 18 | "data" LONGBLOB, 19 | foreign key ("parent") references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE 20 | ); 21 | 22 | create table "user" 23 | ( 24 | "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, 25 | "username" varchar(32) NOT NULL, 26 | "auth_key" varchar(32) NOT NULL, 27 | "password_hash" varchar(256) NOT NULL, 28 | "password_reset_token" varchar(256), 29 | "email" varchar(256) NOT NULL, 30 | "status" integer not null default 10, 31 | "created_at" integer not null, 32 | "updated_at" integer not null 33 | ); 34 | -------------------------------------------------------------------------------- /models/Assignment.php: -------------------------------------------------------------------------------- 1 | id = $id; 35 | $this->user = $user; 36 | parent::__construct($config); 37 | } 38 | 39 | /** 40 | * @inheritdoc 41 | */ 42 | public function attributeLabels() 43 | { 44 | return [ 45 | 'id' => Yii::t('rbac-admin', 'ID'), 46 | 'username' => Yii::t('rbac-admin', 'Username'), 47 | 'name' => Yii::t('rbac-admin', 'Name'), 48 | ]; 49 | } 50 | 51 | /** 52 | * Grands a roles from a user. 53 | * 54 | * @param array $items 55 | * 56 | * @return integer number of successful grand 57 | */ 58 | public function assign($items) 59 | { 60 | $manager = Yii::$app->getAuthManager(); 61 | foreach ($items as $name) { 62 | try { 63 | //先查分组 暂未解决重名问题 64 | if ($manager->getGroups($name)) { 65 | $manager->assignGroup($manager->getGroups($name)[0]['group_id'], $this->id); 66 | } else { 67 | $item = $manager->getRole($name); 68 | $item = $item ?: $manager->getPermission($name); 69 | $manager->assign($item, $this->id); 70 | } 71 | } catch (\Exception $exc) { 72 | Yii::error($exc->getMessage(), __METHOD__); 73 | 74 | return false; 75 | } 76 | } 77 | Helper::invalidate(); 78 | 79 | return true; 80 | } 81 | 82 | /** 83 | * Revokes a roles from a user. 84 | * 85 | * @param array $items 86 | * 87 | * @return integer number of successful revoke 88 | */ 89 | public function revoke($items) 90 | { 91 | $manager = Yii::$app->getAuthManager(); 92 | $success = 0; 93 | foreach ($items as $name) { 94 | try { 95 | if ($manager->getGroups($name)) { 96 | $manager->revokeGroup($manager->getGroups($name)[0]['group_id'], $this->id); 97 | $success++; 98 | } else { 99 | $item = $manager->getRole($name); 100 | $item = $item ?: $manager->getPermission($name); 101 | $manager->revoke($item, $this->id); 102 | $success++; 103 | } 104 | } catch (\Exception $exc) { 105 | Yii::error($exc->getMessage(), __METHOD__); 106 | } 107 | } 108 | Helper::invalidate(); 109 | 110 | return $success; 111 | } 112 | 113 | /** 114 | * 分配列表 115 | * 116 | * @return array 117 | */ 118 | public function getItemsList() 119 | { 120 | $manager = Yii::$app->getAuthManager(); 121 | $available = []; 122 | //角色 123 | foreach ($manager->getRoles() as $name) { 124 | $available[$name->name]['type'] = 'role'; 125 | $available[$name->name]['description'] = $name->description; 126 | $available[$name->name]['check'] = 0; 127 | } 128 | //权限 129 | foreach ($manager->getPermissions() as $name) { 130 | $available[$name->name]['type'] = $name->name[0] == '/' ? 'route' : 'permission'; 131 | $available[$name->name]['description'] = $name->description; 132 | $available[$name->name]['check'] = 0; 133 | } 134 | //分组 135 | $user_groups = array_column($manager->getGroupChild($this->id), 'group_id'); 136 | $groups = $manager->getGroups(); 137 | foreach ($groups as &$v) { 138 | $v['name'] = $v['group_name']; 139 | $v['check'] = 0; 140 | $v['description'] = $v['group_id']; 141 | if ($user_groups && in_array($v['group_id'], $user_groups)) { 142 | $v['check'] = 1; 143 | } 144 | unset($v['group_name']); 145 | unset($v['group_id']); 146 | } 147 | $group_list[""] = $groups; 148 | 149 | foreach ($manager->getAssignments($this->id) as $key => $item) { 150 | $available[$key]['check'] = 1; 151 | } 152 | unset($available[$this->name]); 153 | $i = $j = $k = 0; 154 | $role_list = $permission_list = []; 155 | foreach ($available as $key => $val) { 156 | if ($val['type'] == 'role') { 157 | $role_list[$i]['name'] = $key; 158 | $role_list[$i]['check'] = $val['check']; 159 | $role_list[$i]['description'] = $val['description']; 160 | $i++; 161 | } 162 | if ($val['type'] == 'permission') { 163 | $permission_list[$j]['name'] = $key; 164 | $permission_list[$j]['check'] = $val['check']; 165 | $permission_list[$j]['description'] = $val['description']; 166 | $j++; 167 | } 168 | } 169 | $role_list = ArrayHelper::index($role_list, null, 'parent_name'); 170 | $permission_list = ArrayHelper::index($permission_list, null, 'parent_name'); 171 | $result = ['角色' => $role_list, '权限' => $permission_list, '分组' => $group_list]; 172 | 173 | return $result; 174 | } 175 | 176 | /** 177 | * Get all avaliable and assigned roles/permission 178 | * 179 | * @return array 180 | */ 181 | public function getItems() 182 | { 183 | $manager = Yii::$app->getAuthManager(); 184 | $avaliable = []; 185 | foreach (array_keys($manager->getRoles()) as $name) { 186 | $avaliable[$name] = 'role'; 187 | } 188 | 189 | foreach (array_keys($manager->getPermissions()) as $name) { 190 | if ($name[0] != '/') { 191 | $avaliable[$name] = 'permission'; 192 | } 193 | } 194 | 195 | $assigned = []; 196 | foreach ($manager->getAssignments($this->id) as $item) { 197 | $assigned[$item->roleName] = $avaliable[$item->roleName]; 198 | unset($avaliable[$item->roleName]); 199 | } 200 | 201 | return [ 202 | 'avaliable' => $avaliable, 203 | 'assigned' => $assigned 204 | ]; 205 | } 206 | 207 | /** 208 | * @inheritdoc 209 | */ 210 | public function __get($name) 211 | { 212 | if ($this->user) { 213 | return $this->user->$name; 214 | } 215 | } 216 | 217 | public function findModel($id, $class) 218 | { 219 | if (($user = $class::findIdentity($id)) !== null) { 220 | return new Assignment($id, $user); 221 | } else { 222 | return false; 223 | } 224 | } 225 | 226 | public function Lists($params, $usernameField) 227 | { 228 | $query = $this->find; 229 | $dataProvider = new ActiveDataProvider([ 230 | 'query' => $query, 231 | ]); 232 | if ( !($this->load($params) && $this->validate())) { 233 | return $dataProvider; 234 | } 235 | $query->andFilterWhere(['like', $usernameField, $this->username]); 236 | 237 | return $dataProvider; 238 | } 239 | 240 | /** 241 | * 角色批量分配给用户 242 | * 243 | * @param $users 244 | * 245 | * @return int 246 | */ 247 | public function assignBatch($users) 248 | { 249 | $manager = Yii::$app->getAuthManager(); 250 | $success = 0; 251 | foreach ($users as $user_id) { 252 | try { 253 | $item = $manager->getRole($this->id); 254 | $manager->assign($item, $user_id); 255 | $success++; 256 | } catch (\Exception $exc) { 257 | Yii::error($exc->getMessage(), __METHOD__); 258 | } 259 | } 260 | Helper::invalidate(); 261 | 262 | return $success; 263 | } 264 | 265 | /** 266 | * 可选用户|已分配用户 267 | * 268 | * @return array 269 | */ 270 | public function assignUser() 271 | { 272 | $manager = Yii::$app->getAuthManager(); 273 | $assign = $manager->getAssignmentsUsers($this->id); 274 | $user_id_arr = array_filter(array_column($assign, 'id')); 275 | $user_model = new \wind\rest\models\searchs\User(); 276 | $all = $user_model->allUsers(['id', 'realname']); 277 | foreach ($all as $key => $val) { 278 | if (in_array($val['id'], $user_id_arr)) { 279 | unset($all[$key]); 280 | } 281 | } 282 | sort($all); 283 | 284 | return compact(['all', 'assign']); 285 | } 286 | 287 | /** 288 | * 角色批量删除用户 289 | * 290 | * @param $users 291 | * 292 | * @return int 293 | */ 294 | public function assignRemoveUsers($users) 295 | { 296 | $manager = Yii::$app->getAuthManager(); 297 | $success = 0; 298 | foreach ($users as $user_id) { 299 | try { 300 | $item = $manager->getRole($this->id); 301 | $manager->revoke($item, $user_id); 302 | $success++; 303 | } catch (\Exception $exc) { 304 | Yii::error($exc->getMessage(), __METHOD__); 305 | } 306 | } 307 | Helper::invalidate(); 308 | 309 | return $success; 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /models/AuthGroups.php: -------------------------------------------------------------------------------- 1 | id = $id; 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | public static function tableName() 33 | { 34 | return Yii::$app->authManager->groupTable; 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | */ 40 | public function rules() 41 | { 42 | return [ 43 | [['group_id'], 'string', 'max' => 50], 44 | [['group_name'], 'string', 'max' => 100], 45 | [['group_status'], 'string', 'max' => 50] 46 | ]; 47 | } 48 | 49 | /** 50 | * @inheritdoc 51 | */ 52 | public function attributeLabels() 53 | { 54 | return [ 55 | 'group_id' => '分组ID', 56 | 'group_name' => '分组名称', 57 | 'group_status' => '分组状态', 58 | ]; 59 | } 60 | 61 | /** 62 | * 可用列表 63 | * @param null $is_all 是否查询所有分组 64 | * 65 | * @return array|\yii\db\ActiveRecord[] 66 | */ 67 | public function lists($is_all = null) 68 | { 69 | $model = clone $this; 70 | $query = $model->find(); 71 | $query->select(['group_id', 'group_name']); 72 | if ( !$is_all) { 73 | $query->andWhere(['group_status' => self::STATUS_OPEN]); 74 | } 75 | $result = $query->asArray()->all(); 76 | 77 | return $result; 78 | } 79 | 80 | /** 81 | * 分配添加 82 | * 83 | * @param $id 84 | * 85 | * @return bool 86 | */ 87 | public function assign() 88 | { 89 | $data = Yii::$app->getRequest()->post(); 90 | foreach ($data as $val) { 91 | try { 92 | $group_child_model = new AuthGroupsChild(); 93 | $group_child_model->add($this->id, $val); 94 | } catch (\Exception $exc) { 95 | Yii::error($exc->getMessage(), __METHOD__); 96 | } 97 | } 98 | Helper::invalidate(); 99 | 100 | return true; 101 | } 102 | 103 | /** 104 | * 分配删除 105 | * 106 | * @param $id 107 | * 108 | * @return bool 109 | */ 110 | public function revoke() 111 | { 112 | $data = Yii::$app->getRequest()->post(); 113 | foreach ($data as $val) { 114 | try { 115 | $group_child_model = new AuthGroupsChild(); 116 | $group_child_model->remove($this->id, $val); 117 | } catch (\Exception $exc) { 118 | Yii::error($exc->getMessage(), __METHOD__); 119 | } 120 | } 121 | Helper::invalidate(); 122 | 123 | return true; 124 | } 125 | 126 | /** 127 | * 分配用户列表 128 | * 129 | * @return array 130 | */ 131 | public function assignUser($single_group = null) 132 | { 133 | $group_child_model = new AuthGroupsChild(); 134 | //assign 已分配的 135 | $assign = $group_child_model->assigned($this->id); 136 | if ($single_group) { 137 | $assign_filter = $group_child_model->assignedAll(); 138 | } else { 139 | $assign_filter = $assign; 140 | } 141 | $user_id_arr = array_filter(array_column($assign_filter, 'id')); 142 | //all 所有 143 | $user_model = new \wind\rest\models\searchs\User(); 144 | $all = $user_model->allUsers(['id', 'realname']); 145 | foreach ($all as $key => $val) { 146 | if (in_array($val['id'], $user_id_arr)) { 147 | unset($all[$key]); 148 | } 149 | } 150 | sort($all); 151 | 152 | return compact(['all', 'assign']); 153 | } 154 | 155 | /** 156 | * 添加 157 | * 158 | * @param $group_id 159 | * @param $group_name 160 | * 161 | * @return bool 162 | */ 163 | public function create($group_id, $group_name) 164 | { 165 | $model = $this::findOne(['group_id' => $group_id]) ?: clone $this; 166 | $model->group_id = $group_id; 167 | $model->group_name = $group_name; 168 | if ( !$model->save()) { 169 | \Yii::error($model->errors); 170 | 171 | return false; 172 | } 173 | 174 | return true; 175 | } 176 | 177 | /** 178 | * 停用|启用 179 | * 180 | * @param $group_id 181 | * @param $group_status 182 | * 183 | * @return bool 184 | */ 185 | public function status($group_id, $group_status) 186 | { 187 | $model = $this::findOne(['group_id' => $group_id]); 188 | $model->group_id = $group_id; 189 | $model->group_status = $group_status; 190 | if ( !$model->save()) { 191 | \Yii::error($model->errors); 192 | 193 | return false; 194 | } 195 | 196 | return true; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /models/AuthGroupsChild.php: -------------------------------------------------------------------------------- 1 | authManager->groupChildTable; 23 | } 24 | 25 | /** 26 | * @inheritdoc 27 | */ 28 | public function rules() 29 | { 30 | return [ 31 | [['group_id'], 'string', 'max' => 50], 32 | [['user_id'], 'string', 'max' => 64], 33 | ]; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public function attributeLabels() 40 | { 41 | return [ 42 | 'group_id' => 'GROUP ID', 43 | 'user_id' => '用户id', 44 | ]; 45 | } 46 | 47 | /** 48 | * 关联用户表 49 | * 50 | * @return \yii\db\ActiveQuery 51 | */ 52 | public function getUser() 53 | { 54 | return $this->hasOne(User::className(), ['id' => 'user_id']); 55 | } 56 | 57 | /** 58 | * 添加分组下用户 59 | * 60 | * @param $data 61 | * 62 | * @return bool 63 | */ 64 | public function add($group_id, $user_id) 65 | { 66 | $model = clone $this; 67 | $model->group_id = $group_id; 68 | $model->user_id = $user_id; 69 | 70 | return $model->save(); 71 | } 72 | 73 | /** 74 | * 移除分组下用户 75 | * 76 | * @param $data 77 | * 78 | * @return bool 79 | */ 80 | public function remove($group_id, $user_id) 81 | { 82 | if (empty($user_id)) { 83 | return false; 84 | } 85 | $model = clone $this; 86 | $result = $model->deleteAll(['user_id' => $user_id, 'group_id' => $group_id]); 87 | 88 | return $result; 89 | } 90 | 91 | /** 92 | * 分组下用户 93 | * 94 | * @param $group_id 95 | * 96 | * @return array|\yii\db\ActiveRecord[] 97 | */ 98 | public function assigned($group_id) 99 | { 100 | $model = clone $this; 101 | $query = $model->find(); 102 | $query->joinWith('user', false, 'RIGHT JOIN'); 103 | $query->select(['user.id', 'realname']); 104 | $query->andWhere(['group_id' => $group_id]); 105 | $result = $query->asArray()->all(); 106 | 107 | return $result; 108 | } 109 | 110 | /** 111 | * 所有已分组的用户 112 | * 113 | * @return array|\yii\db\ActiveRecord[] 114 | */ 115 | public function assignedAll() 116 | { 117 | $model = clone $this; 118 | $query = $model->find(); 119 | 120 | return $query->asArray()->all(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /models/AuthItem.php: -------------------------------------------------------------------------------- 1 | 25 | * @since 1.0 26 | */ 27 | class AuthItem extends Model 28 | { 29 | 30 | public $name; 31 | public $type; 32 | public $description; 33 | public $ruleName; 34 | public $data; 35 | public $parent; 36 | /** 37 | * @var Item 38 | */ 39 | public $_item; 40 | 41 | /** 42 | * Initialize object 43 | * 44 | * @param Item $item 45 | * @param array $config 46 | */ 47 | public function __construct($item = null, $config = []) 48 | { 49 | $this->_item = $item; 50 | if ($item !== null) { 51 | $this->name = $item->name; 52 | $this->type = $item->type; 53 | $this->description = $item->description; 54 | $this->ruleName = $item->ruleName; 55 | $this->data = $item->data === null ? null : Json::encode($item->data); 56 | } 57 | parent::__construct($config); 58 | } 59 | 60 | /** 61 | * @inheritdoc 62 | */ 63 | public function rules() 64 | { 65 | return [ 66 | [['ruleName'], 'checkRule'], 67 | [['name', 'type'], 'required'], 68 | [ 69 | ['name'], 70 | 'checkUnique', 71 | 'when' => function () { 72 | return $this->isNewRecord || ($this->_item->name != $this->name); 73 | } 74 | ], 75 | [['type'], 'integer'], 76 | [['description', 'data', 'ruleName'], 'default'], 77 | [['name'], 'string', 'max' => 64] 78 | ]; 79 | } 80 | 81 | /** 82 | * Check role is unique 83 | */ 84 | public function checkUnique() 85 | { 86 | $authManager = Yii::$app->authManager; 87 | $value = $this->name; 88 | if ($authManager->getRole($value) !== null || $authManager->getPermission($value) !== null) { 89 | $this->addError('name'); 90 | } 91 | } 92 | 93 | /** 94 | * Check for rule 95 | */ 96 | public function checkRule() 97 | { 98 | $name = $this->ruleName; 99 | if ( !Yii::$app->getAuthManager()->getRule($name)) { 100 | try { 101 | $rule = Yii::createObject($name); 102 | if ($rule instanceof \yii\rbac\Rule) { 103 | $rule->name = $name; 104 | Yii::$app->getAuthManager()->add($rule); 105 | } else { 106 | $this->addError('ruleName', Yii::t('rbac-admin', 'Invalid rule "{value}"', ['value' => $name])); 107 | } 108 | } catch (\Exception $exc) { 109 | $this->addError('ruleName', Yii::t('rbac-admin', 'Rule "{value}" does not exists', ['value' => $name])); 110 | } 111 | } 112 | } 113 | 114 | /** 115 | * @inheritdoc 116 | */ 117 | public function attributeLabels() 118 | { 119 | return [ 120 | 'name' => Yii::t('rbac-admin', 'Name'), 121 | 'type' => Yii::t('rbac-admin', 'Type'), 122 | 'description' => Yii::t('rbac-admin', 'Description'), 123 | 'ruleName' => Yii::t('rbac-admin', 'Rule Name'), 124 | 'data' => Yii::t('rbac-admin', 'Data'), 125 | ]; 126 | } 127 | 128 | /** 129 | * Check if is new record. 130 | * 131 | * @return boolean 132 | */ 133 | public function getIsNewRecord() 134 | { 135 | return $this->_item === null; 136 | } 137 | 138 | /** 139 | * Find role 140 | * 141 | * @param string $id 142 | * 143 | * @return null|\self 144 | */ 145 | public static function find($id) 146 | { 147 | $item = Yii::$app->authManager->getRole($id); 148 | if ($item !== null) { 149 | return new self($item); 150 | } 151 | 152 | return null; 153 | } 154 | 155 | /** 156 | * Save role to [[\yii\rbac\authManager]] 157 | * 158 | * @return boolean 159 | */ 160 | public function save() 161 | { 162 | if ($this->validate()) { 163 | $manager = Yii::$app->authManager; 164 | if ($this->_item === null) { 165 | if ($this->type == Item::TYPE_ROLE) { 166 | $this->_item = $manager->createRole($this->name); 167 | } else { 168 | $this->_item = $manager->createPermission($this->name); 169 | } 170 | $isNew = true; 171 | } else { 172 | $isNew = false; 173 | $oldName = $this->_item->name; 174 | } 175 | $this->_item->name = $this->name; 176 | $this->_item->description = $this->description; 177 | $this->_item->ruleName = $this->ruleName; 178 | $this->_item->data = $this->data === null || $this->data === '' ? null : Json::decode($this->data); 179 | if ($isNew) { 180 | $manager->add($this->_item); 181 | } else { 182 | $manager->update($oldName, $this->_item); 183 | } 184 | Helper::invalidate(); 185 | 186 | return true; 187 | } else { 188 | return false; 189 | } 190 | } 191 | 192 | /** 193 | * Adds an item as a child of another item. 194 | * 195 | * @param array $items 196 | * 197 | * @return int 198 | */ 199 | public function addChildren($items) 200 | { 201 | $manager = Yii::$app->getAuthManager(); 202 | $success = 0; 203 | if ($this->_item) { 204 | foreach ($items as $name) { 205 | $child = $manager->getPermission($name); 206 | if ($this->type == Item::TYPE_ROLE && $child === null) { 207 | $child = $manager->getRole($name); 208 | } 209 | try { 210 | $manager->addChild($this->_item, $child); 211 | $success++; 212 | } catch (\Exception $exc) { 213 | Yii::error($exc->getMessage(), __METHOD__); 214 | } 215 | } 216 | } 217 | if ($success > 0) { 218 | Helper::invalidate(); 219 | } 220 | 221 | return $success; 222 | } 223 | 224 | /** 225 | * Remove an item as a child of another item. 226 | * 227 | * @param array $items 228 | * 229 | * @return int 230 | */ 231 | public function removeChildren($items) 232 | { 233 | $manager = Yii::$app->getAuthManager(); 234 | $success = 0; 235 | if ($this->_item !== null) { 236 | foreach ($items as $name) { 237 | $child = $manager->getPermission($name); 238 | if ($this->type == Item::TYPE_ROLE && $child === null) { 239 | $child = $manager->getRole($name); 240 | } 241 | try { 242 | $manager->removeChild($this->_item, $child); 243 | $success++; 244 | } catch (\Exception $exc) { 245 | Yii::error($exc->getMessage(), __METHOD__); 246 | } 247 | } 248 | } 249 | if ($success > 0) { 250 | Helper::invalidate(); 251 | } 252 | 253 | return $success; 254 | } 255 | 256 | /** 257 | * 获取可用的权限 258 | * 259 | * @return array 260 | */ 261 | public function getItems() 262 | { 263 | $manager = Yii::$app->getAuthManager(); 264 | $res = []; 265 | foreach ($manager->getPermissions() as $name) { 266 | $route['name'] = $name->name; 267 | $route['description'] = $name->description; 268 | $route['ruleName'] = $name->ruleName; 269 | $route['data'] = $name->data; 270 | $route['type'] = $name->type; 271 | $res[] = $route; 272 | $manager = Yii::$app->getAuthManager(); 273 | $available = []; 274 | if ($this->type == Item::TYPE_ROLE) { 275 | foreach (array_keys($manager->getRoles()) as $role) { 276 | $available[$role] = 'role'; 277 | } 278 | } 279 | } 280 | 281 | return $res; 282 | } 283 | 284 | /** 285 | * 分配列表 286 | * 287 | * @return array 288 | */ 289 | public function getItemsList() 290 | { 291 | $manager = Yii::$app->getAuthManager(); 292 | $available = []; 293 | if ($this->type == Item::TYPE_ROLE) { 294 | foreach ($manager->getRoles() as $name) { 295 | $available[$name->name]['type'] = 'role'; 296 | $available[$name->name]['description'] = $name->description; 297 | $available[$name->name]['parent_name'] = $name->parent_name; 298 | $available[$name->name]['check'] = 0; 299 | } 300 | } 301 | foreach ($manager->getPermissions() as $name) { 302 | $available[$name->name]['type'] = $name->name[0] == '/' ? 'route' : 'permission'; 303 | $available[$name->name]['description'] = $name->description; 304 | $available[$name->name]['parent_name'] = $name->parent_name; 305 | $available[$name->name]['check'] = 0; 306 | } 307 | foreach ($manager->getChildren($this->_item->name) as $item) { 308 | $available[$item->name]['check'] = 1; 309 | } 310 | unset($available[$this->name]); 311 | $i = $j = $k = 0; 312 | $role_list = $permission_list = $route_list = []; 313 | foreach ($available as $key => $val) { 314 | if ($val['type'] == 'role') { 315 | $role_list[$i]['name'] = $key; 316 | $role_list[$i]['check'] = $val['check']; 317 | $role_list[$i]['description'] = $val['description']; 318 | $role_list[$i]['parent_name'] = $val['parent_name']; 319 | $role_list[$i]['show'] = $key; 320 | $i++; 321 | } 322 | if ($val['type'] == 'permission') { 323 | $permission_list[$j]['name'] = $key; 324 | $permission_list[$j]['check'] = $val['check']; 325 | $permission_list[$j]['description'] = $val['description']; 326 | $permission_list[$j]['parent_name'] = $val['parent_name']; 327 | $permission_list[$j]['show'] = $key; 328 | $j++; 329 | } 330 | if ($val['type'] == 'route') { 331 | $route_list[$k]['name'] = $key; 332 | $route_list[$k]['check'] = $val['check']; 333 | $route_list[$k]['description'] = $val['description']; 334 | $route_list[$k]['parent_name'] = $val['parent_name']; 335 | $route_list[$k]['show'] = $val['description']; 336 | $k++; 337 | } 338 | } 339 | $role_list = ArrayHelper::index($role_list, null, 'parent_name'); 340 | $permission_list = ArrayHelper::index($permission_list, null, 'parent_name'); 341 | $route_list = ArrayHelper::index($route_list, null, 'parent_name'); 342 | $result = ['角色' => $role_list, '权限' => $permission_list,'路由' => $route_list]; 343 | if ($this->type == Item::TYPE_PERMISSION) { 344 | unset($result['角色']); 345 | } 346 | 347 | return $result; 348 | } 349 | 350 | /** 351 | * Get item 352 | * 353 | * @return Item 354 | */ 355 | public function getItem() 356 | { 357 | return $this->_item; 358 | } 359 | 360 | /** 361 | * Get type name 362 | * 363 | * @param mixed $type 364 | * 365 | * @return string|array 366 | */ 367 | public static function getTypeName($type = null) 368 | { 369 | $result = [ 370 | Item::TYPE_PERMISSION => 'Permission', 371 | Item::TYPE_ROLE => 'Role' 372 | ]; 373 | if ($type === null) { 374 | return $result; 375 | } 376 | 377 | return $result[$type]; 378 | } 379 | 380 | /** 381 | * 权限 | 角色 添加 382 | * 383 | * @param $type 384 | * 385 | * @return bool|\wind\rest\models\AuthItem 386 | */ 387 | public function addPermission($type) 388 | { 389 | $model = clone $this; 390 | $model->type = $type; 391 | if ($model->load(Yii::$app->getRequest()->post(), '') && $model->save()) { 392 | return $type == 1 ? $model : true; 393 | } else { 394 | RbacHelper::recordLog($model->errors, 'create', 'addPermissionRole'); 395 | 396 | return false; 397 | } 398 | } 399 | 400 | /** 401 | * 权限详情 402 | * 403 | * @param $id 404 | * 405 | * @return bool|\wind\rest\models\AuthItem 406 | */ 407 | public function findModel($id, $type = 2) 408 | { 409 | $auth = Yii::$app->getAuthManager(); 410 | $item = $type === Item::TYPE_ROLE ? $auth->getRole($id) : $auth->getPermission($id); 411 | if ($item) { 412 | return new AuthItem($item); 413 | } else { 414 | return false; 415 | } 416 | } 417 | 418 | /** 419 | * 修改 420 | * 421 | * @param $id 422 | * @param $type 423 | * 424 | * @return bool 425 | */ 426 | public function updatePermission($id, $type) 427 | { 428 | $model = $this->findModel($id, $type); 429 | if ($model->load(Yii::$app->getRequest()->post(), '') && $model->save()) { 430 | return true; 431 | } else { 432 | RbacHelper::recordLog($model->errors, 'update', 'updatePermissionRole'); 433 | 434 | return false; 435 | } 436 | } 437 | 438 | /** 439 | * 删除权限 440 | * 441 | * @param $id 442 | * 443 | * @return bool 444 | */ 445 | public function deletePermission($id, $type) 446 | { 447 | $model = $this->findModel($id, $type); 448 | if ( !$model) { 449 | return false; 450 | } 451 | $res = Yii::$app->getAuthManager()->remove($model->_item); 452 | 453 | return $res; 454 | } 455 | 456 | /** 457 | * 给权限 添加/删除 路由(左边到右边) 458 | * 459 | * @param $id 460 | * @param $type_id 461 | * @param $type 462 | * 463 | * @return array 464 | */ 465 | public function assignItem($id, $type_id, $type) 466 | { 467 | $items = Yii::$app->getRequest()->post(); 468 | $model = $this->findModel($id, $type_id); 469 | if ($type == 'add') { 470 | $model->addChildren($items); 471 | } 472 | if ($type == 'remove') { 473 | $model->removeChildren($items); 474 | } 475 | 476 | return $model->getItems(); 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /models/BizRule.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0 13 | */ 14 | class BizRule extends \yii\base\Model 15 | { 16 | /** 17 | * @var string name of the rule 18 | */ 19 | public $name; 20 | 21 | /** 22 | * @var integer UNIX timestamp representing the rule creation time 23 | */ 24 | public $createdAt; 25 | 26 | /** 27 | * @var integer UNIX timestamp representing the rule updating time 28 | */ 29 | public $updatedAt; 30 | 31 | /** 32 | * @var string Rule classname. 33 | */ 34 | public $className; 35 | 36 | /** 37 | * @var Rule 38 | */ 39 | private $_item; 40 | 41 | /** 42 | * Initilaize object 43 | * @param \yii\rbac\Rule $item 44 | * @param array $config 45 | */ 46 | public function __construct($item, $config = []) 47 | { 48 | $this->_item = $item; 49 | if ($item !== null) { 50 | $this->name = $item->name; 51 | $this->className = get_class($item); 52 | } 53 | parent::__construct($config); 54 | } 55 | 56 | /** 57 | * @inheritdoc 58 | */ 59 | public function rules() 60 | { 61 | return [ 62 | [['name', 'className'], 'required'], 63 | [['className'], 'string'], 64 | [['className'], 'classExists'] 65 | ]; 66 | } 67 | 68 | /** 69 | * Validate class exists 70 | */ 71 | public function classExists() 72 | { 73 | if (!class_exists($this->className)) { 74 | $message = Yii::t('rbac-admin', "Unknown class '{class}'", ['class' => $this->className]); 75 | $this->addError('className', $message); 76 | return; 77 | } 78 | if (!is_subclass_of($this->className, Rule::className())) { 79 | $message = Yii::t('rbac-admin', "'{class}' must extend from 'yii\rbac\Rule' or its child class", [ 80 | 'class' => $this->className]); 81 | $this->addError('className', $message); 82 | } 83 | } 84 | 85 | /** 86 | * @inheritdoc 87 | */ 88 | public function attributeLabels() 89 | { 90 | return [ 91 | 'name' => Yii::t('rbac-admin', 'Name'), 92 | 'className' => Yii::t('rbac-admin', 'Class Name'), 93 | ]; 94 | } 95 | 96 | /** 97 | * Check if new record. 98 | * @return boolean 99 | */ 100 | public function getIsNewRecord() 101 | { 102 | return $this->_item === null; 103 | } 104 | 105 | /** 106 | * Find model by id 107 | * @param type $id 108 | * @return null|static 109 | */ 110 | public static function find($id) 111 | { 112 | $item = Yii::$app->getAuthManager()->getRule($id); 113 | if ($item !== null) { 114 | return new static($item); 115 | } 116 | 117 | return null; 118 | } 119 | 120 | /** 121 | * Save model to authManager 122 | * @return boolean 123 | */ 124 | public function save() 125 | { 126 | if ($this->validate()) { 127 | $manager = Yii::$app->getAuthManager(); 128 | $class = $this->className; 129 | if ($this->_item === null) { 130 | $this->_item = new $class(); 131 | $isNew = true; 132 | } else { 133 | $isNew = false; 134 | $oldName = $this->_item->name; 135 | } 136 | $this->_item->name = $this->name; 137 | 138 | if ($isNew) { 139 | $manager->add($this->_item); 140 | } else { 141 | $manager->update($oldName, $this->_item); 142 | } 143 | 144 | return true; 145 | } 146 | 147 | return false; 148 | } 149 | 150 | /** 151 | * Get item 152 | * @return Item 153 | */ 154 | public function getItem() 155 | { 156 | return $this->_item; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /models/Menu.php: -------------------------------------------------------------------------------- 1 | 25 | * @since 1.0 26 | */ 27 | class Menu extends \yii\db\ActiveRecord 28 | { 29 | 30 | public $parent_name; 31 | public $description; 32 | 33 | /** 34 | * @inheritdoc 35 | */ 36 | public static function tableName() 37 | { 38 | return Configs::instance()->menuTable; 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public static function getDb() 45 | { 46 | if (Configs::instance()->db !== null) { 47 | return Configs::instance()->db; 48 | } else { 49 | return parent::getDb(); 50 | } 51 | } 52 | 53 | /** 54 | * @inheritdoc 55 | */ 56 | public function rules() 57 | { 58 | return [ 59 | [['name'], 'required'], 60 | [ 61 | ['parent_name'], 62 | 'in', 63 | 'range' => static::find()->select(['name'])->column(), 64 | 'message' => 'Menu "{value}" not found.' 65 | ], 66 | [['parent', 'route', 'data', 'order', 'remark'], 'default'], 67 | [ 68 | ['parent'], 69 | 'filterParent', 70 | 'when' => function () { 71 | return !$this->isNewRecord; 72 | } 73 | ], 74 | [['order'], 'integer'], 75 | [ 76 | ['route'], 77 | 'in', 78 | 'range' => static::getSavedRoutes(), 79 | 'message' => 'Route "{value}" not found.' 80 | ] 81 | ]; 82 | } 83 | 84 | /** 85 | * 添加菜单 86 | * 87 | * @return bool|\wind\rest\models\Menu 88 | */ 89 | public function create() 90 | { 91 | $model = new Menu; 92 | $model->load(Yii::$app->request->post(), ''); 93 | if ($model->save()) { 94 | Helper::invalidate(); 95 | 96 | return $model; 97 | } else { 98 | RbacHelper::recordLog($model->errors, 'create', 'Menu'); 99 | 100 | return false; 101 | } 102 | } 103 | 104 | /** 105 | * Use to loop detected.(使用循环检测) 106 | */ 107 | public function filterParent() 108 | { 109 | $parent = $this->parent; 110 | $db = static::getDb(); 111 | $query = (new Query)->select(['parent']) 112 | ->from(static::tableName()) 113 | ->where('[[id]]=:id'); 114 | while ($parent) { 115 | if ($this->id == $parent) { 116 | $this->addError('parent_name', 'Loop detected.'); 117 | 118 | return; 119 | } 120 | $parent = $query->params([':id' => $parent])->scalar($db); 121 | } 122 | } 123 | 124 | /** 125 | * @inheritdoc 126 | */ 127 | public function attributeLabels() 128 | { 129 | return [ 130 | 'id' => 'id',//Yii::t('rbac-admin', 'ID'), 131 | 'name' => 'name',//Yii::t('rbac-admin', 'Name'), 132 | 'parent' => 'parent',//Yii::t('rbac-admin', 'Parent'), 133 | 'parent_name' => 'parent_name',//Yii::t('rbac-admin', 'Parent Name'), 134 | 'route' => 'route',//Yii::t('rbac-admin', 'Route'), 135 | 'order' => 'order',//Yii::t('rbac-admin', 'Order'), 136 | 'data' => 'data',//Yii::t('rbac-admin', 'Data'), 137 | 'remark' => 'remark',//Yii::t('rbac-admin', 'Data'), 138 | ]; 139 | } 140 | 141 | /** 142 | * Get menu parent 143 | * 144 | * @return \yii\db\ActiveQuery 145 | */ 146 | public function getMenuParent() 147 | { 148 | return $this->hasOne(Menu::className(), ['id' => 'parent']); 149 | } 150 | 151 | /** 152 | * Get menu children 153 | * 154 | * @return \yii\db\ActiveQuery 155 | */ 156 | public function getMenus() 157 | { 158 | return $this->hasMany(Menu::className(), ['parent' => 'id']); 159 | } 160 | 161 | private static $_routes; 162 | 163 | /** 164 | * Get saved routes. 165 | * 166 | * @return array 167 | */ 168 | public static function getSavedRoutes() 169 | { 170 | if (self::$_routes === null) { 171 | self::$_routes = []; 172 | foreach (Yii::$app->getAuthManager()->getPermissions() as $name => $value) { 173 | if ($name[0] === '/' && substr($name, -1) != '*') { 174 | self::$_routes[] = $name; 175 | } 176 | } 177 | } 178 | 179 | return self::$_routes; 180 | } 181 | 182 | /** 183 | * 菜单列表 184 | * 185 | * @return array 186 | */ 187 | public function getMenuSource() 188 | { 189 | $tableName = static::tableName(); 190 | $res = (new \yii\db\Query())->select([ 191 | 'm.id', 192 | 'm.name', 193 | 'm.route', 194 | 'parent_name' => 'p.name', 195 | 'm.order', 196 | 'm.remark', 197 | 'a.description as route_name' 198 | ]) 199 | ->from(['m' => $tableName]) 200 | ->leftJoin(['p' => $tableName], '[[m.parent]]=[[p.id]]') 201 | ->leftJoin(['a' => 'auth_item'], '`m`.`route`= CONVERT(`a`.`name` USING utf8) COLLATE utf8_unicode_ci') 202 | ->all(static::getDb()); 203 | 204 | return $res; 205 | } 206 | 207 | /** 208 | * 菜单详情 209 | * 210 | * @param $id 211 | * 212 | * @return bool|\wind\rest\models\Menu 213 | */ 214 | public function findModel($id) 215 | { 216 | if (($model = $this::findOne($id)) !== null) { 217 | $model->parent_name = $model->menuParent->name ?? null; 218 | $manager = Yii::$app->authManager; 219 | if ($model->route) { 220 | $model->description = $manager->getPermission($model->route)->description ?? ''; 221 | } 222 | 223 | return $model; 224 | } else { 225 | return false; 226 | } 227 | } 228 | 229 | /** 230 | * 更新 231 | * 232 | * @param $id 233 | * 234 | * @return bool|\wind\rest\models\Menu 235 | */ 236 | public function updateMenu($id) 237 | { 238 | $model = $this->findModel($id); 239 | if ($model->menuParent) { 240 | $model->parent_name = $model->menuParent->name; 241 | } 242 | 243 | if ($model->load(Yii::$app->request->post(), '') && $model->save()) { 244 | Helper::invalidate(); 245 | 246 | return $model; 247 | } else { 248 | RbacHelper::recordLog($model->errors, 'update', 'Menu'); 249 | 250 | return false; 251 | } 252 | } 253 | 254 | /** 255 | * 删除 256 | * 257 | * @param $id 258 | * 259 | * @return bool|int 260 | */ 261 | public function deleteMenu($id) 262 | { 263 | $res = $this->findModel($id)->delete(); 264 | 265 | return $res; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /models/Permission.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class Permission extends \yii\rbac\Permission 17 | { 18 | 19 | /** 20 | * @inheritdoc 21 | */ 22 | public $parent_name; 23 | } 24 | -------------------------------------------------------------------------------- /models/Role.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class Role extends \yii\rbac\Role 19 | { 20 | /** 21 | * @inheritdoc 22 | */ 23 | public $parent_name; 24 | } 25 | -------------------------------------------------------------------------------- /models/Route.php: -------------------------------------------------------------------------------- 1 | getAuthManager(); 34 | foreach ($routes as $val) { 35 | $route = $val['name']; 36 | try { 37 | $r = explode('&', $route); 38 | $item = $manager->createPermission('/' . trim($route, '/')); 39 | if (count($r) > 1) { 40 | $action = '/' . trim($r[0], '/'); 41 | if (($itemAction = $manager->getPermission($action)) === null) { 42 | $itemAction = $manager->createPermission($action); 43 | $manager->add($itemAction); 44 | } 45 | unset($r[0]); 46 | foreach ($r as $part) { 47 | $part = explode('=', $part); 48 | $item->data['params'][$part[0]] = isset($part[1]) ? $part[1] : ''; 49 | } 50 | $this->setDefaultRule(); 51 | $item->ruleName = RouteRule::RULE_NAME; 52 | $item->description = $val['description']; 53 | $item->parent_name = $val['parent_name']; 54 | $manager->add($item); 55 | $manager->addChild($item, $itemAction); 56 | } else { 57 | $item->description = $val['description']; 58 | $item->parent_name = $val['parent_name']; 59 | $manager->add($item); 60 | } 61 | } catch (Exception $exc) { 62 | Yii::error($exc->getMessage(), __METHOD__); 63 | } 64 | } 65 | Helper::invalidate(); 66 | } 67 | 68 | /** 69 | * Assign or remove items(删除节点) 70 | * 71 | * @param array $routes 72 | * 73 | * @return array 74 | */ 75 | public function remove($routes) 76 | { 77 | $manager = Yii::$app->getAuthManager(); 78 | foreach ($routes as $route) { 79 | try { 80 | //获取auth_item 表中全部信息 81 | $item = $manager->createPermission('/' . trim($route, '/')); 82 | $manager->remove($item); 83 | } catch (Exception $exc) { 84 | Yii::error($exc->getMessage(), __METHOD__); 85 | } 86 | } 87 | Helper::invalidate(); 88 | } 89 | 90 | /** 91 | * Get avaliable and assigned routes(获得指定/可使用的route) 92 | * 93 | * @return array 94 | */ 95 | public function getRoutes() 96 | { 97 | $manager = Yii::$app->getAuthManager(); 98 | // $routes = $this->getAppRoutes(); 99 | $exists = []; 100 | foreach ($manager->getPermissions() as $name) { 101 | $name = ArrayHelper::toArray($name); 102 | if ($name['name'][0] !== '/') { 103 | continue; 104 | } 105 | $route['name'] = $name['name']; 106 | $route['description'] = $name['description']; 107 | $route['parent_name'] = $name['parent_name']; 108 | $exists[] = $route; 109 | // unset($routes[$name['name']]); 110 | } 111 | $exists = ArrayHelper::index($exists, null, 'parent_name'); 112 | 113 | return [ 114 | // 'avaliable' => array_keys($routes), 115 | 'assigned' => $exists 116 | ]; 117 | } 118 | 119 | // /** 120 | // * Get avaliable and assigned routes(获得指定/可使用的route) 121 | // * 122 | // * @return array 123 | // */ 124 | // public function getAll() 125 | // { 126 | // $manager = Yii::$app->getAuthManager(); 127 | // $routes = $this->getAppRoutes(); 128 | // $exists = []; 129 | // foreach ($manager->getPermissions() as $name) { 130 | // $route['name'] = $name->name; 131 | // $route['description'] = $name->description; 132 | // $exists[] = $route; 133 | // unset($routes[$name->name]); 134 | // } 135 | // 136 | // return array_keys($routes); 137 | // } 138 | 139 | /** 140 | * Get list of application routes 141 | * 142 | * @return array 143 | */ 144 | public function getAppRoutes($module = null) 145 | { 146 | if ($module === null) { 147 | $module = Yii::$app; 148 | } elseif (is_string($module)) { 149 | $module = Yii::$app->getModule($module); 150 | } 151 | $key = [__METHOD__, $module->getUniqueId()]; 152 | $cache = Configs::instance()->cache; 153 | if ($cache === null || ($result = $cache->get($key)) === false) { 154 | $result = []; 155 | $this->getRouteRecrusive($module, $result); 156 | if ($cache !== null) { 157 | $cache->set($key, $result, Configs::instance()->cacheDuration, new TagDependency([ 158 | 'tags' => self::CACHE_TAG, 159 | ])); 160 | } 161 | } 162 | 163 | return $result; 164 | } 165 | 166 | /** 167 | * Get route(s) recrusive 168 | * 169 | * @param \yii\base\Module $module 170 | * @param array $result 171 | */ 172 | protected function getRouteRecrusive($module, &$result) 173 | { 174 | $token = "Get Route of '" . get_class($module) . "' with id '" . $module->uniqueId . "'"; 175 | Yii::beginProfile($token, __METHOD__); 176 | try { 177 | foreach ($module->getModules() as $id => $child) { 178 | if (($child = $module->getModule($id)) !== null) { 179 | $this->getRouteRecrusive($child, $result); 180 | } 181 | } 182 | 183 | foreach ($module->controllerMap as $id => $type) { 184 | $this->getControllerActions($type, $id, $module, $result); 185 | } 186 | 187 | $namespace = trim($module->controllerNamespace, '\\') . '\\'; 188 | $this->getControllerFiles($module, $namespace, '', $result); 189 | $all = '/' . ltrim($module->uniqueId . '/*', '/'); 190 | $result[$all] = $all; 191 | } catch (\Exception $exc) { 192 | Yii::error($exc->getMessage(), __METHOD__); 193 | } 194 | Yii::endProfile($token, __METHOD__); 195 | } 196 | 197 | /** 198 | * Get list controller under module 199 | * 200 | * @param \yii\base\Module $module 201 | * @param string $namespace 202 | * @param string $prefix 203 | * @param mixed $result 204 | * 205 | * @return mixed 206 | */ 207 | protected function getControllerFiles($module, $namespace, $prefix, &$result) 208 | { 209 | $path = Yii::getAlias('@' . str_replace('\\', '/', $namespace), false); 210 | $token = "Get controllers from '$path'"; 211 | Yii::beginProfile($token, __METHOD__); 212 | try { 213 | if ( !is_dir($path)) { 214 | return; 215 | } 216 | foreach (scandir($path) as $file) { 217 | if ($file == '.' || $file == '..') { 218 | continue; 219 | } 220 | if (is_dir($path . '/' . $file) && preg_match('%^[a-z0-9_/]+$%i', $file . '/')) { 221 | $this->getControllerFiles($module, $namespace . $file . '\\', $prefix . $file . '/', $result); 222 | } elseif (strcmp(substr($file, -14), 'Controller.php') === 0) { 223 | $baseName = substr(basename($file), 0, -14); 224 | $name = strtolower(preg_replace('/(?getControllerActions($className, $prefix . $id, $module, $result); 231 | } 232 | } 233 | } 234 | } catch (\Exception $exc) { 235 | Yii::error($exc->getMessage(), __METHOD__); 236 | } 237 | Yii::endProfile($token, __METHOD__); 238 | } 239 | 240 | /** 241 | * Get list action of controller 242 | * 243 | * @param mixed $type 244 | * @param string $id 245 | * @param \yii\base\Module $module 246 | * @param string $result 247 | */ 248 | protected function getControllerActions($type, $id, $module, &$result) 249 | { 250 | $token = "Create controller with cofig=" . VarDumper::dumpAsString($type) . " and id='$id'"; 251 | Yii::beginProfile($token, __METHOD__); 252 | try { 253 | /* @var $controller \yii\base\Controller */ 254 | $controller = Yii::createObject($type, [$id, $module]); 255 | $this->getActionRoutes($controller, $result); 256 | $all = "/{$controller->uniqueId}/*"; 257 | $result[$all] = $all; 258 | } catch (\Exception $exc) { 259 | Yii::error($exc->getMessage(), __METHOD__); 260 | } 261 | Yii::endProfile($token, __METHOD__); 262 | } 263 | 264 | /** 265 | * Get route of action 266 | * 267 | * @param \yii\base\Controller $controller 268 | * @param array $result all controller action. 269 | */ 270 | protected function getActionRoutes($controller, &$result) 271 | { 272 | $token = "Get actions of controller '" . $controller->uniqueId . "'"; 273 | Yii::beginProfile($token, __METHOD__); 274 | try { 275 | $prefix = '/' . $controller->uniqueId . '/'; 276 | foreach ($controller->actions() as $id => $value) { 277 | $result[$prefix . $id] = $prefix . $id; 278 | } 279 | $class = new \ReflectionClass($controller); 280 | foreach ($class->getMethods() as $method) { 281 | $name = $method->getName(); 282 | if ($method->isPublic() && !$method->isStatic() && strpos($name, 283 | 'action') === 0 && $name !== 'actions' 284 | ) { 285 | $name = strtolower(preg_replace('/(?getMessage(), __METHOD__); 292 | } 293 | Yii::endProfile($token, __METHOD__); 294 | } 295 | 296 | /** 297 | * Ivalidate cache 298 | */ 299 | public static function invalidate() 300 | { 301 | if (Configs::cache() !== null) { 302 | TagDependency::invalidate(Configs::cache(), self::CACHE_TAG); 303 | } 304 | } 305 | 306 | /** 307 | * Set default rule of parameterize route. 308 | */ 309 | protected function setDefaultRule() 310 | { 311 | if (Yii::$app->getAuthManager()->getRule(RouteRule::RULE_NAME) === null) { 312 | Yii::$app->getAuthManager()->add(new RouteRule()); 313 | } 314 | } 315 | 316 | /** 317 | * 父级路由名称 318 | * 319 | * @return array 320 | */ 321 | public function parentList() 322 | { 323 | $manager = Yii::$app->getAuthManager(); 324 | $result = $manager->getRouteParent(); 325 | $result = array_column($result, 'parent_name'); 326 | 327 | return $result; 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /models/User.php: -------------------------------------------------------------------------------- 1 | userTable; 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function behaviors() 45 | { 46 | return [ 47 | TimestampBehavior::className(), 48 | ]; 49 | } 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | public function rules() 55 | { 56 | return [ 57 | ['status', 'default', 'value' => self::STATUS_ACTIVE], 58 | ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE]], 59 | ]; 60 | } 61 | 62 | /** 63 | * @inheritdoc 64 | */ 65 | public static function findIdentity($id) 66 | { 67 | return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); 68 | } 69 | 70 | /** 71 | * @inheritdoc 72 | */ 73 | public static function findIdentityByAccessToken($token, $type = null) 74 | { 75 | throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); 76 | } 77 | 78 | /** 79 | * Finds user by username 80 | * 81 | * @param string $username 82 | * @return static|null 83 | */ 84 | public static function findByUsername($username) 85 | { 86 | return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); 87 | } 88 | 89 | /** 90 | * Finds user by password reset token 91 | * 92 | * @param string $token password reset token 93 | * @return static|null 94 | */ 95 | public static function findByPasswordResetToken($token) 96 | { 97 | if (!static::isPasswordResetTokenValid($token)) { 98 | return null; 99 | } 100 | 101 | return static::findOne([ 102 | 'password_reset_token' => $token, 103 | 'status' => self::STATUS_ACTIVE, 104 | ]); 105 | } 106 | 107 | /** 108 | * Finds out if password reset token is valid 109 | * 110 | * @param string $token password reset token 111 | * @return boolean 112 | */ 113 | public static function isPasswordResetTokenValid($token) 114 | { 115 | if (empty($token)) { 116 | return false; 117 | } 118 | $expire = Yii::$app->params['user.passwordResetTokenExpire']; 119 | $parts = explode('_', $token); 120 | $timestamp = (int) end($parts); 121 | return $timestamp + $expire >= time(); 122 | } 123 | 124 | /** 125 | * @inheritdoc 126 | */ 127 | public function getId() 128 | { 129 | return $this->getPrimaryKey(); 130 | } 131 | 132 | /** 133 | * @inheritdoc 134 | */ 135 | public function getAuthKey() 136 | { 137 | return $this->auth_key; 138 | } 139 | 140 | /** 141 | * @inheritdoc 142 | */ 143 | public function validateAuthKey($authKey) 144 | { 145 | return $this->getAuthKey() === $authKey; 146 | } 147 | 148 | /** 149 | * Validates password 150 | * 151 | * @param string $password password to validate 152 | * @return boolean if password provided is valid for current user 153 | */ 154 | public function validatePassword($password) 155 | { 156 | return Yii::$app->security->validatePassword($password, $this->password_hash); 157 | } 158 | 159 | /** 160 | * Generates password hash from password and sets it to the model 161 | * 162 | * @param string $password 163 | */ 164 | public function setPassword($password) 165 | { 166 | $this->password_hash = Yii::$app->security->generatePasswordHash($password); 167 | } 168 | 169 | /** 170 | * Generates "remember me" authentication key 171 | */ 172 | public function generateAuthKey() 173 | { 174 | $this->auth_key = Yii::$app->security->generateRandomString(); 175 | } 176 | 177 | /** 178 | * Generates new password reset token 179 | */ 180 | public function generatePasswordResetToken() 181 | { 182 | $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); 183 | } 184 | 185 | /** 186 | * Removes password reset token 187 | */ 188 | public function removePasswordResetToken() 189 | { 190 | $this->password_reset_token = null; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /models/form/Login.php: -------------------------------------------------------------------------------- 1 | hasErrors()) { 45 | $user = $this->getUser(); 46 | if (!$user || !$user->validatePassword($this->password)) { 47 | $this->addError($attribute, 'Incorrect username or password.'); 48 | } 49 | } 50 | } 51 | 52 | /** 53 | * Logs in a user using the provided username and password. 54 | * 55 | * @return boolean whether the user is logged in successfully 56 | */ 57 | public function login() 58 | { 59 | if ($this->validate()) { 60 | return Yii::$app->getUser()->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); 61 | } else { 62 | return false; 63 | } 64 | } 65 | 66 | /** 67 | * Finds user by [[username]] 68 | * 69 | * @return User|null 70 | */ 71 | public function getUser() 72 | { 73 | if ($this->_user === false) { 74 | $this->_user = User::findByUsername($this->username); 75 | } 76 | 77 | return $this->_user; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /models/searchs/Assignment.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0 14 | */ 15 | class Assignment extends Model 16 | { 17 | public $id; 18 | public $username; 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | public function rules() 24 | { 25 | return [ 26 | [['id', 'username'], 'safe'], 27 | ]; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public function attributeLabels() 34 | { 35 | return [ 36 | 'id' => Yii::t('rbac-admin', 'ID'), 37 | 'username' => Yii::t('rbac-admin', 'Username'), 38 | 'name' => Yii::t('rbac-admin', 'Name'), 39 | ]; 40 | } 41 | 42 | /** 43 | * Create data provider for Assignment model. 44 | * @param array $params 45 | * @param \yii\db\ActiveRecord $class 46 | * @param string $usernameField 47 | * @return \yii\data\ActiveDataProvider 48 | */ 49 | public function search($params, $class, $usernameField) 50 | { 51 | $query = $class::find(); 52 | $dataProvider = new ActiveDataProvider([ 53 | 'query' => $query, 54 | ]); 55 | 56 | if (!($this->load($params) && $this->validate())) { 57 | return $dataProvider; 58 | } 59 | 60 | $query->andFilterWhere(['like', $usernameField, $this->username]); 61 | 62 | return $dataProvider; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /models/searchs/AuthItem.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0 15 | */ 16 | class AuthItem extends Model 17 | { 18 | 19 | const TYPE_ROUTE = 101; 20 | 21 | public $name; 22 | public $type; 23 | public $description; 24 | public $ruleName; 25 | public $data; 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function rules() 31 | { 32 | return [ 33 | [['name', 'ruleName', 'description'], 'safe'], 34 | [['type'], 'integer'], 35 | ]; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function attributeLabels() 42 | { 43 | return [ 44 | 'name' => Yii::t('rbac-admin', 'Name'), 45 | 'item_name' => Yii::t('rbac-admin', 'Name'), 46 | 'type' => Yii::t('rbac-admin', 'Type'), 47 | 'description' => Yii::t('rbac-admin', 'Description'), 48 | 'ruleName' => Yii::t('rbac-admin', 'Rule Name'), 49 | 'data' => Yii::t('rbac-admin', 'Data'), 50 | ]; 51 | } 52 | 53 | /** 54 | * Search AuthItem 55 | * 56 | * @param array $params 57 | * 58 | * @return \yii\data\ActiveDataProvider|\yii\data\ArrayDataProvider 59 | */ 60 | public function search($params) 61 | { 62 | /* @var \yii\rbac\BaseManager $authManager */ 63 | $authManager = Yii::$app->getAuthManager(); 64 | if ($this->type == Item::TYPE_ROLE) { 65 | $items = $authManager->getRoles(); 66 | } else { 67 | $items = array_filter($authManager->getPermissions(), function ($item) { 68 | return $this->type == Item::TYPE_PERMISSION xor strncmp($item->name, '/', 1) === 0; 69 | }); 70 | } 71 | $this->load($params); 72 | if ($this->validate()) { 73 | $search = strtolower(trim($this->name)); 74 | $desc = strtolower(trim($this->description)); 75 | $ruleName = $this->ruleName; 76 | foreach ($items as $name => $item) { 77 | $f = (empty($search) || strpos(strtolower($item->name), $search) !== false) && 78 | (empty($desc) || strpos(strtolower($item->description), $desc) !== false) && 79 | (empty($ruleName) || $item->ruleName == $ruleName); 80 | if ( !$f) { 81 | unset($items[$name]); 82 | } 83 | } 84 | } 85 | $items = array_values($items); 86 | // sort($items); 87 | 88 | return $items; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /models/searchs/BizRule.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 1.0 19 | */ 20 | class BizRule extends Model 21 | { 22 | /** 23 | * @var string name of the rule 24 | */ 25 | public $name; 26 | public $data; 27 | 28 | public function rules() 29 | { 30 | return [ 31 | [['name'], 'safe'] 32 | ]; 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | public function attributeLabels() 39 | { 40 | return [ 41 | 'name' => Yii::t('rbac-admin', 'Name'), 42 | ]; 43 | } 44 | 45 | /** 46 | * Search BizRule 47 | * @param array $params 48 | * @return \yii\data\ActiveDataProvider|\yii\data\ArrayDataProvider 49 | */ 50 | public function search($params) 51 | { 52 | /* @var \yii\rbac\Manager $authManager */ 53 | $authManager = Yii::$app->authManager; 54 | $models = []; 55 | $included = !($this->load($params) && $this->validate() && trim($this->name) !== ''); 56 | foreach ($authManager->getRules() as $name => $item) { 57 | if ($name != RouteRule::RULE_NAME && ($included || stripos($item->name, $this->name) !== false)) { 58 | $models[$name] = new MBizRule($item); 59 | } 60 | } 61 | 62 | return new ArrayDataProvider([ 63 | 'allModels' => $models, 64 | ]); 65 | } 66 | 67 | public function save() 68 | { 69 | if ($this->validate()) { 70 | $manager = Yii::$app->authManager; 71 | if ($this->_item === null) { 72 | if ($this->type == Item::TYPE_ROLE) { 73 | $this->_item = $manager->createRole($this->name); 74 | } else { 75 | $this->_item = $manager->createPermission($this->name); 76 | } 77 | $isNew = true; 78 | } else { 79 | $isNew = false; 80 | $oldName = $this->_item->name; 81 | } 82 | $this->_item->name = $this->name; 83 | $this->_item->description = $this->description; 84 | $this->_item->ruleName = $this->ruleName; 85 | $this->_item->data = $this->data === null || $this->data === '' ? null : Json::decode($this->data); 86 | if ($isNew) { 87 | $manager->add($this->_item); 88 | } else { 89 | $manager->update($oldName, $this->_item); 90 | } 91 | Helper::invalidate(); 92 | 93 | return true; 94 | } else { 95 | return false; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /models/searchs/Menu.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0 14 | */ 15 | class Menu extends MenuModel 16 | { 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | public function rules() 22 | { 23 | return [ 24 | [['id', 'parent', 'order'], 'integer'], 25 | [['name', 'route', 'parent_name'], 'safe'], 26 | ]; 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | public function scenarios() 33 | { 34 | // bypass scenarios() implementation in the parent class 35 | return Model::scenarios(); 36 | } 37 | 38 | /** 39 | * Searching menu 40 | * 41 | * @param array $params 42 | * 43 | * @return \yii\data\ActiveDataProvider 44 | */ 45 | public function search($params) 46 | { 47 | $query = MenuModel::find() 48 | ->from(MenuModel::tableName() . ' t') 49 | ->joinWith([ 50 | 'menuParent' => function ($q) { 51 | $q->from(MenuModel::tableName() . ' parent'); 52 | } 53 | ]); 54 | 55 | // $dataProvider = new ActiveDataProvider([ 56 | // 'query' => $query 57 | // ]); 58 | // 59 | // $sort = $dataProvider->getSort(); 60 | // $sort->attributes['menuParent.name'] = [ 61 | // 'asc' => ['parent.name' => SORT_ASC], 62 | // 'desc' => ['parent.name' => SORT_DESC], 63 | // 'label' => 'parent', 64 | // ]; 65 | // 66 | // $sort->attributes['order'] = [ 67 | // 'asc' => ['parent.order' => SORT_ASC, 't.order' => SORT_ASC], 68 | // 'desc' => ['parent.order' => SORT_DESC, 't.order' => SORT_DESC], 69 | // 'label' => 'order', 70 | // ]; 71 | // $sort->defaultOrder = ['menuParent.name' => SORT_ASC]; 72 | // if ( !($this->load($params) && $this->validate())) { 73 | // return $dataProvider; 74 | // } 75 | 76 | $query->andFilterWhere([ 77 | 't.id' => $this->id, 78 | 't.parent' => $this->parent, 79 | ]); 80 | 81 | $query->andFilterWhere(['like', 'lower(t.name)', strtolower($this->name)]) 82 | ->andFilterWhere(['like', 't.route', $this->route]) 83 | ->andFilterWhere(['like', 'lower(parent.name)', strtolower($this->parent_name)]); 84 | 85 | return $query->asArray()->all(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /models/searchs/User.php: -------------------------------------------------------------------------------- 1 | setAttributes($params); 44 | $status = $this->status ?: parent::STATUS_ACTIVE; 45 | $query->andFilterWhere([ 46 | 'id' => $this->id, 47 | 'created_at' => $this->created_at, 48 | 'updated_at' => $this->updated_at, 49 | ]); 50 | $query->select([ 51 | "id", 52 | "username", 53 | "realname", 54 | "email", 55 | "status", 56 | "created_at", 57 | ]); 58 | $query->andFilterWhere(['like', 'username', $this->username]); 59 | $query->andFilterWhere(['like', 'email', $this->email]); 60 | $query->andFilterWhere(['status' => $status]); 61 | $query->orderBy(['id' => 'asc']); 62 | $result = $query->asArray()->all(); 63 | foreach ($result as $key => $value) { 64 | if ($value['created_at']) { 65 | $result[$key]['created_at'] = date('Y年m月d日', $value['created_at']); 66 | } else { 67 | $result[$key]['created_at'] = '--'; 68 | } 69 | } 70 | 71 | return $result; 72 | } 73 | 74 | public function allUsers($select = '*') 75 | { 76 | $query = UserModel::find(); 77 | $query->select($select); 78 | $query->andWhere(['status' => parent::STATUS_ACTIVE]); 79 | $result = $query->asArray()->all(); 80 | 81 | return $result; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /rule/BelongShopRule.php: -------------------------------------------------------------------------------- 1 | request->get('shop_id'); 27 | if (empty($shop_id)) { 28 | return true; 29 | } 30 | $shop_ids = Yii::$app->user->identity->groups; 31 | if ( !strstr($shop_ids, $shop_id)) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | } --------------------------------------------------------------------------------