[英]Using CakePHP to build web apps with subdomains
我正在使用CakePHP构建一个Web应用程序,该应用程序将允许用户为其公司/组织创建子域。 例如company-name.domain.com
为此,我有一个Users表和一个Subsites表,如下所示:
用户:ID,用户名,电子邮件,密码,subsite_id子站点:ID,名称,域
如您所见,用户链接到子站点,并且子站点通过这种关系可以有许多用户,但是用户只能属于一个子站点。
我在AppController中使用以下命令检查子域是否有效:
function checkSubdomain()
{
if ($_SERVER['HTTP_HOST'] != 'domain.com')
{
$domain_parts = explode('.',$_SERVER['HTTP_HOST']);
if (count($domain_parts) != 3) exit('Invalid url');
$subdomain = $domain_parts[0];
$this->loadModel('Subsite');
$subsites = $this->Subsite->find('all', array('conditions'=>array('domain'=>$subdomain)));
if(empty($subsites))
{
exit('Subsite not found');
}
}
}
function beforeFilter()
{
$this->checkSubdomain();
}
这基本上是说,如果未找到子域,则会出错,这很好! 我遇到的问题是,出于某些明显原因,我希望子域无法访问诸如主页,关于,定价和注册表单的某些页面。
最好的方法是什么? 无需检查我所有的控制器是否是子域?
我注意到诸如getballpark.com之类的其他应用程序在注册过程中使用了子域。 它们是允许某些子域具有某些页面的一种特殊方法吗?
谢谢
根据以下答案的其他要求,如果正在使用子域,则会阻止对某些控制器的访问:
另一个问题是,如果用户登录,我将使用HomeController来显示启动页面或应用程序的仪表板。问题是我要说的是,如果通过进行访问,则必须仅登录该方法子域。 或者它们是实现sam功能的完全更好的解决方案。
为了保护注册(位于我的UsersController中),我还将阻止登录并忘记密码方法。 我该如何解决而又不必破坏Cake约定并将方法移至单个控制器? 干杯
我建议列出禁止的控制器列表,然后在应用程序控制器的beforeFilter
处理程序中进行检查,以防当前请求来自子域:
protected $_forbiddenSubdomainControllers = array
(
'about',
'home',
'pricing',
'signup'
);
public function beforeFilter()
{
parent::beforeFilter();
if($this->checkSubdomain() &&
in_array($this->request->params['controller'], $this->_forbiddenSubdomainControllers))
{
throw new ForbiddenException('This URL is inaccessible');
}
}
public function checkSubdomain()
{
if ($_SERVER['HTTP_HOST'] != 'domain.com')
{
$domain_parts = explode('.',$_SERVER['HTTP_HOST']);
if (count($domain_parts) != 3) exit('Invalid url');
$subdomain = $domain_parts[0];
$this->loadModel('Subsite');
$subsites = $this->Subsite->find('all', array('conditions'=>array('domain'=>$subdomain)));
if(empty($subsites))
{
throw new NotFoundException('Subsite not found');
}
return true;
}
return false;
}
请注意,我已经更改了checkSubdomain
方法,以便根据请求是否来自(有效)子域来返回true
或false
,并且我还将您的exit
调用更改为抛出错误,这是CakePHP中的首选方式处理这种情况。
如果要允许某些子域使用这些“特殊”控制器中的某些,则建议将允许的控制器存储在数据库中并将它们与Subsite
模型相关联,然后可以在检查中包括这些名称。
编辑(05.11.2012)
仅当从子域请求时才要求对特定AuthComponent::allow
身份验证,例如,可以使用AuthComponent::allow
来实现。 在Home
控制器中的beforeFilter
回调中,您可以检查子域,然后适当地允许/拒绝未经身份验证的访问。 例如,允许所有操作,以防请求不是来自子域:
public function beforeFilter()
{
parent::beforeFilter();
if(!$this->checkSubdomain())
{
$this->Auth->allow('*');
}
}
考虑到要限制对特定操作的访问的新要求,我想说,根据应用程序的复杂性,限制/授予访问权限可能是ACL的工作。
相反,“手动”执行此操作,我的第一个示例可以通过操作进行扩展,例如:
protected $_denyAccessMap = array
(
'about',
'home',
'pricing',
'users' => array
(
'signup'
)
);
public function beforeFilter()
{
parent::beforeFilter();
if($this->checkSubdomain())
{
$controller = $this->request->params['controller'];
$action = $this->request->params['action'];
if(in_array($controller, $this->_denyAccessMap) ||
(array_key_exists($controller, $this->_denyAccessMap) && in_array($action, $this->_denyAccessMap[$controller])))
{
throw new ForbiddenException('This URL is inaccessible');
}
}
}
这将拒绝访问控制器about
, home
和pricing
,以及对users
控制signup
行为。
如前所述,这也可以使用ACL来完成,并且由于您说需要授予某些子域更多访问权限,因此这可能是更好的选择,它将允许您动态控制访问限制。 看看Simple Acl控制的Application教程 ,您可以轻松地使用它,只需将Group
模型替换为Subsite
模型。
这样,您可以授予特定的子站点访问权限,并因此授予与该子站点相关联的用户访问特定操作的权限,例如,允许id
1
的Subsite
访问所有控制器,但“ Users
控制器” subscribe
方法除外:
$this->Subsite->id = 1;
$this->Acl->allow($this->Subsite, 'controllers');
$this->Acl->deny($this->Subsite, 'controllers/User/subscribe');
或者反过来,阻止对Users
控制器的访问,期望特定的login
和passwordRecovery
恢复操作:
$this->Acl->allow($this->Subsite, 'controllers');
$this->Acl->deny($this->Subsite, 'controllers/User');
$this->Acl->allow($this->Subsite, 'controllers/User/login');
$this->Acl->allow($this->Subsite, 'controllers/User/passwordRecovery');
然后可以例如在应用程序控制器中的beforeFilter
回调中检查是否允许访问:
public function beforeFilter()
{
parent::beforeFilter();
$subsite = $this->checkSubdomain();
if(!empty($subsite))
{
$aco = 'controllers/' . $this->name . '/' . $this->request->params['action'];
if($this->Acl->check($subsite, $aco))
{
throw new ForbiddenException('This URL is inaccessible');
}
}
}
public function checkSubdomain()
{
if ($_SERVER['HTTP_HOST'] != 'domain.com')
{
$domain_parts = explode('.',$_SERVER['HTTP_HOST']);
if (count($domain_parts) != 3) exit('Invalid url');
$subdomain = $domain_parts[0];
$this->loadModel('Subsite');
$subsite = $this->Subsite->find('first', array('conditions'=>array('domain'=>$subdomain)));
if(empty($subsite))
{
throw new NotFoundException('Subsite not found');
}
return $subsite;
}
return false;
}
请注意,我已经更改了checkSubdomain
方法,以便它返回find
结果或false
以便可以轻松地将其用于ACL检查。
除了主要的问题和答案外,我还将考虑开发环境...由于几天前我遇到了类似的问题,因此我进行了研究,这是我的工作:
在AppController内部:
function checkAccess() {
if (count($domain_parts) != 3 &&
(count($domain_parts) == 2 && $domain_parts[1] != 'localhost:8080')) {
throw new NotFoundException();
}
}
内部checkSubdomain()方法:
checkSubdomain() {
[...]
$this->checkAccess();
[...]
}
由于我正在localhost上测试子域功能,因此可以使用xxx.localhost和yyy.localhost并在部署之前检查一切正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.