qeephp权限 相反打勾了没有权限访问

单行、唯一 0     1923      框架   0     0
多次在后台勾选权限的时候,多个角色同时打勾的时候,会出现打勾后相反没有权限的问题,经过调试找出了问题的所在


普通用户是不能访问后台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,问题解决


问题解决


captcha
忘记密码? 注册
第三方登录
微信赞赏
支付宝赞赏