I am building a web app using CakePHP that will allow users to create subdomains for their company / organisations. For example company-name.domain.com
To achieve this I have a Users table and a Subsites table like so:
Users: id, username, email, password, subsite_id
Subsites: id, name, domain
As you can see Users are linked to subsites and subsites can have many users through this relationship, but users can only belong to one subsite.
I check if a subdomain is valid using the following in 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();
}
This basically says if a subdomain IS NOT found then error out, which works fine! The problem I have is that I want certain pages like home, about, pricing and signup forms to not be accessible for subdomains for obvious reasons.
What would be the best way of doing this? Without having to a check in all my controllers if it’s a subdomain or not?
I’ve noticed that other apps like getballpark.com use a subdomain for the signup process. Is their a special way to allow certain subdomains to have certain pages?
Thanks
Additional requirements based on the answer below that blocks access to certain controllers if a subdomain is being used:
One other problem is that I use the HomeController to either show a splash promo page or the dashboard for the app if the user is logged in. The problem is how do I say you must ONLY be logged in for that method if you are accessing via a subdomain. Or is their an entirely better solution for achieving the sam functionality.
In protecting the signup (which is in my UsersController) I’d also be blocking the login and forgot password methods. How do I get around this without having to break Cake convention and move methods to individual controllers? Cheers
I would suggest making a list of forbidden controllers, and then checking against that in the app controllers
beforeFilterhandler in case the current request comes from a subdomain:Note that i’ve changed your
checkSubdomainmethod so that it returnstrueorfalsedepeding on whether the request comes form a (valid) subdomain, and i’ve also changed yourexitcall to throwing an error, which is the prefered way in CakePHP to handle such situations.If you want to allow certain subdomains to use some of these “special” controllers, then i’d suggest to store the allowed controllers in the database and associate them to the
Subsitemodel, then you can include these names in the check.Edit (05.11.2012)
Requiring authentication for specific controlls only when requested from a subdomain, could for example be achieved by using
AuthComponent::allow. In theHomecontrollersbeforeFiltercallback you could check for the subdomain, and then allow/deny non authenticated access appropriately. For example allow all actions in case the request doesn’t come from a subdomain:With your new requirements in mind to restrict access to specific actions, i’d say that depending on the complexity of your application, restricting/granting access might be a job for ACL.
Doing it “manually” instead, my first example could be extended with actions, for example like this:
That would deny access to the controllers
about,homeandpricing, and to theuserscontrollersignupaction.As already mentioned, this could also be done using ACL, and since you said that you need to grant certain subdomains more acceess, this might be the better option, it would allow you to dynamically control the access restrictions. Have a look at the Simple Acl controlled Application tutorial, you could easily use this, you’d just need to replace the
Groupmodel with yourSubsitemodel.That way you could grant specific subsites, and therefore the users associated with that subsites, access to specific actions, for example allow the
Subsitewith theid1access to all controllers, except for theUserscontrollerssubscribemethod:Or the other way around, block access to the
Userscontroller, expect for the specificloginandpasswordRecoveryactions:Checking whether access is allowed could then for example be done in the app controllers
beforeFiltercallback:Note that i’ve changed the
checkSubdomainmethod so that it returns thefindresult orfalseso that it can easily be used for the ACL check.