ACL checks at API level, on a per-method basis
I'm working on a sort of MVC framework, and I'm implementing a simple ACL permissions check system.
I'm wondering if anyone can shed some light on, or direct me towards some good examples of this sort of implementation (or criticize to the point of warranting scrapping it, whichever is necessary)
Since I'm building the framework with REST API in mind, I've created two base controllers, WebController
and ApiController
.
Requests made to /index.php
route to WebController_*
and requests made to /api/index.php
route to ApiController_*
An extended WebController
is responsible for building output from a template with data returned from the consolidated calls to the necessary ApiController
s.
An extended ApiController
is responsible for querying the Model
for data. If a call is made directly to /api/index.php
it returns JSON
.
But I digress; In order to facilitate ACL, I figured implementi开发者_运维百科ng it at the ApiController
layer made sense, and if there is a denial it is returned in JSON
or back up to a WebController
and handled accordingly, depending on the request type.
I'm thinking to simplify things, I could make use of __call()
and private methods. __call()
would verify the existence of the requested method, and prior to calling it, check the user permissions on the method it against the ACL.
class ApiController{
public function __call($method, $arguments){
if(method_exists($this, $method)){
//haven't written ACL classes yet, but something like this
if(ACL::check(...)){
return call_user_func_array(array($this, $method), $arguments);
}else{
return false;
}
}else{
//throw catchable exception or something
}
}
}
Good idea? Bad idea? Thoughts? Maybe I'm in over my head here, I'm still learning and this is more for education than profit, however finishing something that has future use would be nice.
This is a pretty good idea to check credentials in the ApiController
layer but try to kill the magic by avoiding the __call()
method. Yes, this isn't your question but could be useful if you want better performances.
Well, you may use filters like a security filter which handles the request and check the user permissions. The filter could redirect the request to the 401 error response for example. This idea comes from the Symfony Framework.
Regards, William.
I've decided to go with an approach similar to my initially proposed method, creating a Gateway
object to act as a proxy to the Model
. Essentially the Gateway
object holds a reference to the Acl
, Request
, and Model
objects, and performs checks against the Acl
object before forwarding any method calls to the Model
. Simplified for brevity:
public function __call($method, $arguments){
// check request data against acl
if($this->_acl->check($this->_request, $method, $arguments)){
// on success, send request in and forward method to model
$this->_model->setRequest($this->_request);
return call_user_func_array(array($this->_model, $method), $arguments);
}
// acl check failed, no access
return false;
}
Are there any issues that can be seen with this approach? So far as I can tell, this should serve the purpose quite effectively, as I can sub in different Acl
and Model
objects based on the needs of the Controller
(Though likely there will only be the need for a single Acl
)
Furthermore, my routing of API calls becomes simplified, as using a REST/RPC hybrid architecture, API calls can be passed to the Gateway
without much need for modification.
精彩评论