Tuesday, November 30, 2010

Create RESTful Applications Using The Zend Framework - Part III : Managing API Key

n the first two posts of this series, we discussed how to route REST requests to controllers and return HTTP response code. In this article I will talk about managing API keys.
Having the clients send API key within the HTTP header is convenient to handle. We can quickly check the HTTP request header and decide whether to allow or deny the request.
As a prerequisite you should be familiar writing front controller plugins. Let's write a front controller plugin that does the following:
  • Check whether the request has the correct API key in the HTTP header
  • If the correct API key in the HTTP header is missing, set the appropriate HTTP response code and route the request to error controller
We will not perform any changes to our previous article controller.
Let's start writing code.
Step 1: Write the front controller plugin.
Create the directory library/My/Controller/Plugin.
Inform the autoloader about the namespace 'My'. Also, register the plugin "My_Controller_Plugin_RestAuth". Let's add these lines to our configuration file application/configs/application.ini generated by Zend_Tool(or the quick start guide).
autoloadernamespaces.1 = "My_"
resources.frontController.plugins = "My_Controller_Plugin_RestAuth"
Let's write the front controller plugin. Create and edit the file library/My/Controller/Plugin/RestAuth.php


<?phpclass My_Controller_Plugin_RestAuth extends Zend_Controller_Plugin_Abstract{
    public function 
preDispatch(Zend_Controller_Request_Abstract $request)
    {
        
$apiKey $request->getHeader('apikey');

        if (
$apiKey != 'secret') {
            
$this->getResponse()
                    ->
setHttpResponseCode(403)
                    ->
appendBody("Invalid API Key\n")
                    ;
            
$request->setModuleName('default')
                        ->
setControllerName('error')
                        ->
setActionName('access')
                        ->
setDispatched(true);

        }

    }

}
?>
In our front controller plugin, we hook into the preDispatch() method. Before a controller action is executed, our Predispatch() method is called.
In our preDispatch() method, we check whether the HTTP request header contains the key 'apikey' with value 'secret'. If the request does not have the correct API key we set the 403 HTTP response code and set the controller and action to 'error' and 'access' respectively. We also set the dispatched status to true.
Step 2: Add the 'access' action to the error controller in application/controllers/ErrorController.php.

<?phppublic function accessAction()
{
        
$this->_helper->ViewRenderer->setNoRender(true);
}
?>
In the sample code, we simply disable the view. In your application, you could perform logging in the access action of the error controller.
Step 3: Let's test our application using cUrl.
Make a request without sending the 'apikey' HTTP header.
curl http://zfrest.example.com/article -v
The sample output of the above command looks like:

* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> GET /article HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.2
> Host: zfrest.example.com
> Accept: */*
> 
< HTTP/1.1 403 Forbidden
< Date: Mon, 01 Mar 2010 08:46:03 GMT
< Server: Apache/2.2.14 (Fedora)
< X-Powered-By: PHP/5.3.1
< Content-Length: 16
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
Invalid API Key
* Closing connection #0
We recieved the HTTP response code 403 with the body content 'Invalid API Key'.
Let's make another test. This time, let's add the correct API key in the request HTTP header.
curl -H "apikey: secret" http://zfrest.example.com/article -v
Using the -H switch, we can send headers.
The output :

* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> GET /article HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.2
> Host: zfrest.example.com
> Accept: */*
> apikey: secret
> 
< HTTP/1.1 200 OK
< Date: Mon, 01 Mar 2010 08:57:15 GMT
< Server: Apache/2.2.14 (Fedora)
< X-Powered-By: PHP/5.3.1
< Content-Length: 20
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
* Closing connection #0
all articles content
This time we received the HTTP response code 200 with body content 'all articles content'.

No comments:

Post a Comment