I’d like to restrict access to a folder of controllers that are used for admin purposes only. I’ve tried a number of ways and not coming up with a solution. These controllers are behind password protection. But, I’d like to just remove it from view if someone happens to stumble upon the right directory. Can this be done? I’d rather not do it from htaccess. I have access to the apache config files, so I’d like to handle it there.
Does it have anything to do with the way Codeigniter routes? Or, am I just way off?
This what I’m using that doesn’t work
<Directory /var/www/application/controllers/folder/>
Order deny,allow
Deny from all
Allow from xxx.xxx.xxx.xxx
</Directory>
Due to the way we re-write urls to work with CI, you'd never match your Apache config because you're actually requesting index.php?{args}
. If you want to filter, you have to do it in CI instead. Your options are a core controller or hooks.
A simple way to do it is to create a core controller that your admin/ area scripts extend, and check the IP there.
Something like this:
application/core/MY_Controller.php
:
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->config('permitted_ips');
// check visitor IP against $config['ips'] array, redirect as needed
}
}
Then, in your 'sensitive' controllers, extend MY_Controller:
application/controllers/admin/seekrit.php
class Seekrit extends MY_Controller
{
public function __construct() {
parent::__construct();
/* at this point any invalid IP has been redirected */
}
}
Now, if you're already using a core controller for something else, just check $this->uri->segment()
to see if they're in a restricted area before loading the allowed IP configuration file and checking / redirecting / dying or whatever else you need to do.
Also, there's no need to use a constructor in your admin controllers if you don't need one, as the parent will be constructed if one is not defined. Just be sure to call the parent if you define one.
You could also put the white list in a database, Redis, whatever.
Another way to do this would be by using hooks, specifically the pre_controller
hook. By the time that hook is entered, all of the security and base classes have run. This would be appropriate if you wanted to protect some or all of your routes in a more granular fashion. There, you could define an array containing routes, such as:
$protected_routes = array(
'foo' => array(
'allow_ip' => '1.2.3.4',
'redirect_if_not' => site_url('goaway')
)
)
Then, in your hook class (or function) match the first segment (my example is just a function):
$CI = get_instance();
$CI->load-config('my_hook');
$protected_routes = $CI->config->item('protected_routes');
$segment = $CI->uri->segment(1); // foo
if (in_array($segment, $protected_routes)) {
// grab $protected_routes[$segment] and work with it
}
This has the advantage of not cluttering up your core controller as many people use that as a means of sharing code between methods. However, the hook will run on every request which means adding another two file loads to bootstrap.
I used the hook method on a large RESTful service to protect certain endpoints by requiring additional headers, and enforcing different kinds of rate limiting on others. Note, the code above is just an example of what could go in the hook, not how to set up the hook itself. Read the hooks section of the CI manual, it's extremely easy and straight forward.
Finally, if you really want to do it via .htaccess
, you'll have to go by the request itself. The directory application/controllers/foo
is never entered, the actual request is /foo/controller/method{args}
, which causes CI to instantiate the foo/controller.php
class. Remember, once re-written, the server sees index.php?....
To accomplish this, you can re-write based on the request URI pattern, something like this (have not tested, YMMV):
RewriteRule (^|/)foo(/|$) - [F,L]
Which can be used to redirect anyone accessing the virtual path to your protected controllers. This could be preferable as it prevents PHP from needing to handle it, but you lose the granularity of control over what happens when there is a match. Still, you could use something like the above re-write combined with a hook or core implementation if you have more than one sensitive area to protect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With