深入浅析Yii admin的权限控制(3)

  这个导航是我自己改了好多版总结出适合我们自己的方案,其中breadcrumb是控制面包屑的显示,有时间我会抽离php。我介绍的是菜单优化,现在才完成了第一步,菜单的显示,说到优化我是采用缓存菜单数据的策略,就是缓存上面那个$menus_new['list'],策略如下:

  这个策略使用角色缓存数据,就是使用每个角色的权限加上uid和环境配置MD5以后生成key,考虑到用户比较多每个用户都缓存的话开销太大,并且用户相同权限的的比较多,特殊权限的可以特殊对待,这样省去了存储好多重复的数据,环境配置是区分线上数据和测试数据,便于我们进行调试。

  过期机制:更重要的是缓存的过期机制,缓存有了但是当菜单或者权限发生变化的时候就要更新缓存,这里我们引入了版本的概念,能做到缓存变更的最小开销。比如菜单变化,所有人导航都应该修改,这里我们在redis中加入一个导航版本的变量,每次读入缓存的时候都会先判断这个版本与缓存中自己存储版本是否一致,如果一致证明导航没有变化,如果不一致认为菜单有修改,导航已过期,需要重新得到缓存,这样相同的角色,只要有一个人更新了导航,其他人下次再进来的时候就会访问到最新的导航(统一角色)。这个全局的redis变量会在导航变更和权限变更的时候自动加1,保证版本的变化,这样如果有4类角色,几万人的用户,实际的数据修改只发生的4次(实际会比这个多,比如同一个角色不同的权限,那么他对应的redis key 就不一样,它需要自己去取缓存)。具体的代码实现如下:

$user_id = Yii::$app->user->id; $breadcrumb = []; $menus_new['list'] = MenuHelper::getAssignedMenu($user_id); $redis_key = MenuHelper::getMenuKeyByUserId($user_id); $redis_menu = Yii::$app->redis->get($redis_key); $redis_varsion = getVersion(); if (!empty($redis_menu)) { $menus_new = json_decode($redis_menu, true); $old_version = isset($menus_new['version']) ? $menus_new['version'] : ''; //判断菜单的版本号,便于及时更新缓存 if (!isset($menus_new['list']) || empty($old_version) || intval($old_version) != $redis_varsion) { $menus_new = getMenu($user_id, $redis_varsion, $redis_key); $log = json_encode([ 'user_id' => $user_id, 'varsion' => $redis_varsion, 'redis_key' => $redis_key, 'value' => $menus_new ]); writeLog($log, 'update_menu'); } } else { $menus_new = getMenu($user_id, $redis_varsion, $redis_key); } function getMenu($user_id, $varsion, $redis_key) { $menus_new['list'] = MenuHelper::getAssignedMenu($user_id); $menus_new['version'] = $varsion; Yii::$app->redis->set($redis_key, json_encode($menus_new)); Yii::$app->redis->expire($redis_key, 300); return $menus_new; } //设置更新key便于时时更新redis function getVersion() { $version_key = Yii::$app->params['redis_key']['menu_prefix'] . md5(Yii::$app->params['redis_key']['menu_version'] . Yii::$app->db->dsn); $version_val = Yii::$app->redis->get($version_key); return empty($version_val) ? 1 : $version_val; } 生成key和更新key的逻辑如下: /** * get menu one user by the id * @param $user_id * @return key string */ public static function getMenuKeyByUserId($user_id) { if (empty($user_id)) { return false; } $list = (new \yii\db\Query())->select('**') ->from('**') ->where(['user_id' => $user_id]) ->all(); if (empty($list)) { return false; } $role_str = ''; foreach ($list as $key => $value) { $role_str .= $value['item_name']; } $redis_key = Yii::$app->params['key'] . md5($role_str . Yii::$app->db->dsn); return $redis_key; } /** * 修改菜单更新状态,更新redis */ public static function UpdateMenuVersion() { $version_key = Yii::$app->params['key'] . md5(Yii::$app->params['key'] . Yii::$app->db->dsn); $version_val = Yii::$app->redis->get($version_key); if (empty($version_val)) { $version_val = '1'; } else { $version_val++; } $log = json_encode([ 'user_id' => Yii::$app->user->id, 'version_key' => $version_key, 'version_val' => $version_val ]); writeLog($log, 'update_menu_version'); Yii::$app->redis->set($version_key, $version_val); }

2、导航的高亮,图标,是否显示

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/a50fdab610fa5c94ec2ae4d63bbd7bd4.html