qeephp权限 相反打勾了没有权限访问
多次在后台勾选权限的时候,多个角色同时打勾的时候,会出现打勾后相反没有权限的问题,经过调试找出了问题的所在
普通用户是不能访问后台discovery控制器的,信息管理员可以,但是现在存在的问题是,当前用户是信息管理员又是普通用户,就不能访问了,其中一个不能访问,就不能访问。
这个不是我们想要的逻辑,我们需要其中一个能访问,就可以访问。
问题分析解决如下:
首先在myapp.php文件里面
function dispatching()方法里面做了权限控制:
function dispatching(array $args = array()) {
// 构造运行时上下文对象
$context = QContext::instance();
// 获得请求对应的 UDI(统一目的地信息)
$udi = $context->requestUDI('array');
// FDEF DEBUG
QLog::log('REQUEST UDI: ' . $context->UDIString($udi), QLog::DEBUG);
// NDIF
// 检查是否有权限访问
if (!$this->authorizedUDI($this->currentUserRoles(), $udi)) {
// 拒绝访问
if ($context->isAJAX()) {
echo json_encode(array(
'status' => false,
'title' => '无权操作',
'message' => '无权操作,请先登录或换账号登录'
));
exit();
}
else {
$response = $this->_on_access_denied($udi); // @version 1.0.1
}
}
else {
............
}
方法:
/**
* 检查指定角色是否有权限访问特定的控制器和动作
*
* @param array $roles
* @param string|array $udi
*
* @return boolean
*/
function authorizedUDI($roles, $udi) {
/**
* 将 UDI 封装为一个资源
* 读取控制器的 ACL(访问控制列表)
* 通过 QACL 组件进行权限检查
*/
$roles = Q::normalize($roles);
$udi = QContext::instance()->normalizeUDI($udi);
$controller_acl = $this->controllerACL($udi);
// print_r($roles);
// print_r($controller_acl);
// 首先检查动作 ACT
$acl = Q::singleton('QACL');
$action_name = strtolower($udi[QContext::UDI_ACTION]);
if (isset($controller_acl['actions'][$action_name])) { // 如果动作的 ACT 检验通过,则忽略控制器的 ACT
return $acl->rolesBasedCheck($roles, $controller_acl['actions'][$action_name]);
}
if (isset($controller_acl['actions'][QACL::ALL_ACTIONS])) { // 如果为所有动作指定了默认 ACT,则使用该 ACT 进行检查
return $acl->rolesBasedCheck($roles, $controller_acl['actions']['actions'][QACL::ALL_ACTIONS]);
}
// 否则检查是否可以访问指定控制器
return $acl->rolesBasedCheck($roles, $controller_acl);
}
打印出 $roles、 $udi、 $controller_acl如下:
可以看到当前角色是 2和18
当前url是 admin模块discovery控制器和index方法
allow当前url允许访问的角色是1,14,15,18
deny不允许访问的角色是2,3,16,17
所以当前用户角色既在allow,又在deny
此时URL调用的是:
if (isset($controller_acl['actions'][$action_name])) { // 如果动作的 ACT 检验通过,则忽略控制器的 ACT
return $acl->rolesBasedCheck($roles, $controller_acl['actions'][$action_name]);
}
我们再来看看rolesBasedCheck()方法:
<span style="background-color: white; font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;">/**</span><span style="font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;">* 检查访问控制表是否允许指定的角色访问</span>
* * 详细使用说明请参考开发者手册“访问控制”章节。 * * @param array $roles * 要检查的角色 * @param array $acl * 访问控制表 * @param boolean $skip_normalize * 是否跳过对 ACL 的整理 * * @return boolean 检查结果 */ function rolesBasedCheck($roles, $acl, $skip_normalize = false) { $roles = array_map('strtolower', Q::normalize($roles)); if (!$skip_normalize) { $acl = $this->normalize($acl); } if ($acl['allow'] == self::ACL_EVERYONE) { // 如果 allow 允许所有角色,deny 没有设置,则检查通过 if ($acl['deny'] == self::ACL_NULL) { return true; } // 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过 if ($acl['deny'] == self::ACL_NO_ROLE) { if (empty($roles)) { return false; } return true; } // 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过 if ($acl['deny'] == self::ACL_HAS_ROLE) { if (empty($roles)) { return true; } return false; } // 如果 deny 也为 acl_everyone,则表示 acl 出现了冲突 if ($acl['deny'] == self::ACL_EVERYONE) { throw new QACL_Exception('Invalid acl'); } // 只有 deny 中没有用户的角色信息,则检查通过 foreach ($roles as $role) { if (in_array($role, $acl['deny'])) { return false; } } return true; } do { // 如果 allow 要求用户具有角色,但用户没有角色时直接不通过检查 if ($acl['allow'] == self::ACL_HAS_ROLE) { if (!empty($roles)) { break; } return false; } // 如果 allow 要求用户没有角色,但用户有角色时直接不通过检查 if ($acl['allow'] == self::ACL_NO_ROLE) { if (empty($roles)) { break; } return false; } if ($acl['allow'] != self::ACL_NULL) { // 如果 allow 要求用户具有特定角色,则进行检查 $passed = false; foreach ($roles as $role) { if (in_array($role, $acl['allow'])) { $passed = true; break; } } if (!$passed) { return false; }else{ return true; } } } while (false); // 如果 deny 没有设置,则检查通过 if ($acl['deny'] == self::ACL_NULL) { return true; } // 如果 deny 为 acl_no_role,则只要用户具有角色就检查通过 if ($acl['deny'] == self::ACL_NO_ROLE) { if (empty($roles)) { return false; } return true; } // 如果 deny 为 acl_has_role,则只有用户没有角色信息时才检查通过 if ($acl['deny'] == self::ACL_HAS_ROLE) { if (empty($roles)) { return true; } return false; } // 如果 deny 为 acl_everyone,则检查失败 if ($acl['deny'] == self::ACL_EVERYONE) { return false; } // 只有 deny 中没有用户的角色信息,则检查通过 foreach ($roles as $role) { if (in_array($role, $acl['deny'])) { return false; } } return true; }
代码的红色部分是后来添加的,此时忽略没有
根据上面打印的数据,在执行if ($acl['allow'] != self::ACL_NULL)的时候,$passed = true;是成立的,但是
if (!$passed) {
return false;
}
否决了一切,程序往下走 ,直到:
// 只有 deny 中没有用户的角色信息,则检查通过
foreach ($roles as $role) {
if (in_array($role, $acl['deny'])) {
return false;
}
}
走到了deny的检测中,而2的角色是在deny中的,所以返回了false,不通过。
即:以前的设计是优先考虑deny,只要你有一个角色被deny,那你就不能访问
所以添加了 代码的红色部分
由此,优先考虑allow,问题解决
问题解决
请先登录后再评论登录