【发布时间】:2012-07-21 21:44:08
【问题描述】:
我正在开发一个名为 PHP-Bouncer 的 PHP 开源基于角色的访问控制库。 PHP-Bouncer 允许用户定义角色列表,每个角色提供访问哪些页面,并且每个角色还可以定义覆盖其他页面的页面列表(因此转到被覆盖的页面会将您重定向到覆盖页面) .这是一个如何工作的示例(来自文档中的Access Managed Example):
$bouncer = new Bouncer();
// Add a role Name, Array of pages role provides
$bouncer->addRole("Public", array("index.php", "about.php", "fail.php"));
// Add a role Name, Array of pages role provides
$bouncer->addRole("Registered User", array("myaccount.php", "editaccount.php", "viewusers.php"));
// Add a role Name, Array of pages role provides List of pages that are overridden by other pages
$bouncer->addRole("Admin", array("stats.php", "manageusers.php"), array("viewusers.php" => "manageusers.php"));
// Here we add some users. The user class here extends the BouncerUser class, so it can still do whatever you
// would normally create a user class to do..
$publicUser = new User();
$registeredUser = new User();
$adminUser = new User();
$registeredAndAdmin = new User();
$publicUser->addRole("Public");
$registeredUser->addRole("Public"); // We add the public group to all users since they need it to see index.php
$registeredUser->addRole("Registered User");
$adminUser->addRole("Public"); // We add the public group to all users since they need it to see index.php
$adminUser->addRole("Admin");
$registeredAndAdmin->addRole("Public"); // We add the public group to all users since they need it to see index.php
$registeredAndAdmin->addRole("Registered User");
$registeredAndAdmin->addRole("Admin");
$bouncer->manageAccess($publicUser->getRoles(), substr($_SERVER["PHP_SELF"], 1), "fail.php");
这是我遇到的问题:在您在上面看到的 manageAccess 函数中,只要角色定义合理,并且所有用户都可以访问 fail.php(或者 fail.php 没有实现 $bouncer目的)。一旦有人创建了一个具有内在冲突(例如用自身覆盖页面)或未能让所有用户访问失败页面的角色,manageAccess 函数就会导致无限循环。由于这很糟糕,我想修复它。但是,我不确定在防止无限循环的同时,允许一些重定向的最佳方法是什么(重定向最多两次或三次可能是理想的行为是可行的)。这里是 manageAccess 函数:
/**
* @param array $roleList
* @param string $url
* @param string $failPage
*/
public function manageAccess($roleList, $url, $failPage = "index.php"){
$granted = false;
foreach($roleList as $role){
if(array_key_exists($role, $this->roles)){
$obj = $this->roles[$role];
/** @var $obj BouncerRole */
$response = $obj->verifyAccess($url);
if($response->getIsOverridden()){ // If access to the page is overridden forward the user to the overriding page
$loc = ($obj->getOverridingPage($url) !== false) ? $obj->getOverridingPage($url) : $failPage;
$locationString = "Location: ".$loc;
header($locationString);
// I broke something in the last commit, perhaps this comment will help?
}
if($response->getIsAccessible()){ // If this particular role contains access to the page set granted to true
$granted = true; // We don't return yet in case another role overrides.
}
}
}
// If we are here, we know that the page has not been overridden
// so let's check to see if access has been granted by any of our roles.
// If not, the user doesn't have access so we'll forward them on to the failure page.
if(!$granted){
$locationString = "Location: ".$failPage."?url=".urlencode($url)."&roles=".urlencode(serialize($roleList));
header($locationString);
}
}
有什么建议吗?
【问题讨论】:
-
你应该在第一个
header($locationString)之后添加return。 -
这会被执行吗?
-
如果不返回,则可能会发送多个
Location标头。 -
经过一番研究,我发现您在发送位置标头后需要终止是正确的。我选择使用 exit();而不是返回,因为它会阻止页面的其余部分被返回,这是我想要的行为。但是,我真正需要的是一种方法来确保重定向的数量不会失控。如果您尝试将某人重定向到 index.php 而不授予他们访问 index.php 的权限(导致库将他们重定向到失败页面,该页面恰好是 index.php),就会发生这种情况。这更有意义吗?
标签: php infinite-loop access-control rbac