簡體   English   中英

如何使用php身份驗證腳本作為CouchDB的代理,並仍然保持完整的REST API功能?

[英]How do I use a php authentication script as proxy to CouchDB and still maintain full REST API functionality?

我最近已經成功安裝了CouchDB 1.2.1版,作為測試,我可以使用CentOS 6中的以下Apache重寫來訪問它:

RewriteRule couchdb/(.*)$ http://127.0.0.1:5984/$1 [QSA,P]

我有一個PHP身份驗證類,可在自家開發的API中使用它來支持我的移動應用程序。 我的API使用URL中包含的HMAC簽名接受並驗證每個請求,如下所示:

https://api.domain.com/endpoint/?timestamp=[timestamp]&signature=[signature]&id=[id]...etc

每個端點都有一個相應的腳本,可確保在處理之前檢查簽名是否正確。

理想情況下,我想用某種PHP腳本有效地替換上述反向代理重寫規則,該腳本將充當CouchDB實例的網守/網關,利用我的身份驗證類,同時仍保留所有本機CouchDB REST API功能,包括但不限於針對用戶的復制和Cookie身份驗證(以上僅用於API身份驗證)。 能做到嗎? 我嘗試使用解決方案進行以下修改,但實際上它確實會踢回有效的JSON響應,但是復制失敗,並且我懷疑諸如用戶身份驗證之類的其他方面也會起作用:

<?php
require_once('CouchDBProxy.php');
require_once("common.php");

//set some vars
$resource = $_GET['resource'];
$id = $_GET['appid'];
$timestamp = $_GET['timestamp'];
$signature = $_GET['signature'];

//use common class for validating sig
if ( Access::validSignature( $id, $timestamp, $signature ) ) {
    $proxy = new CouchDBProxy('127.0.0.1', '5984');
    $proxy->proxy('/'.$resource);
}
?>


<?php
//COUCHDB_PROXY.PHP

    class CouchDBProxy
    {
        public $host;
        public $port;
        public $timeout = 10;

        /**
         * Initialize the proxy service
         *
         * @param string $host the host where the requests should be forwarded
         * @param string $port the port on the host to use
         * @author Adam Venturella
         */
        public function __construct($host, $port)
        {
            $this->host            = $host;
            $this->port            = $port;
        }

        /**
         * Begin proxying
         *
         * @return void
         * @author Adam Venturella
         */

        public function proxy($resource)
        {
            $verb    = strtolower($_SERVER['REQUEST_METHOD']);
            $command = null;

            switch($verb)
            {
                case 'get':
                    $command = $this->proxy_get($resource);
                    break;

                case 'post':
                    $command = $this->proxy_post($resource);
                    break;

                case 'put':
                    $command = $this->proxy_put($resource);
                    break;

                case 'delete':
                    $command = $this->proxy_delete($resource);
                    break;

                case 'head':
                    $command = $this->proxy_head($resource);
                    break;
            }

            if($command)
            {
                curl_exec($command);
                curl_close($command);
            }
        }

        /**
         * Handle GET requests
         *
         * @return void
         * @author Adam Venturella
         */
        private function proxy_get($resource)
        {
            return $this->request($resource);
        }

        /**
         * Handle HEAD requests
         *
         * @return void
         * @author Adam Venturella
         */
        private function proxy_head($resource)
        {
            $command = $this->request($resource);
            curl_setopt( $command, CURLOPT_NOBODY, true);
            return $command;
        }

        /**
         * Handle POST requests
         *
         * @return void
         * @author Adam Venturella
         */
        private function proxy_post($resource)
        {
            $command = $this->request($resource);
            $data    = file_get_contents("php://input");
            curl_setopt($command, CURLOPT_POST, true);
            curl_setopt($command, CURLOPT_POSTFIELDS, $data);

            return $command;
        }

        /**
         * Handle DELETE Requests
         *
         * @return void
         * @author Adam Venturella
         */
        private function proxy_delete($resource)
        {
            $command = $this->request($resource);
            curl_setopt($command, CURLOPT_CUSTOMREQUEST, 'DELETE');  
            return $command;
        }

        /**
         * Handle PUT requests
         *
         * @return void
         * @author Adam Venturella
         */
        private function proxy_put($resource)
        {
            $command = $this->request($resource);

            $data     = file_get_contents("php://input");
            curl_setopt($command, CURLOPT_CUSTOMREQUEST, 'PUT');  
            curl_setopt($command, CURLOPT_POSTFIELDS, $data);

            return $command;
        }

        /**
         * Build the basic request
         *
         * @return void
         * @author Adam Venturella
         */
        private function request($resource)
        {
            $action    = $_SERVER['REQUEST_METHOD'];
            $uri       = $resource;
    //      $uri       = $_SERVER['REQUEST_URI'];

            $params    = null;

            //added from http://stackoverflow.com/questions/2916232/call-to-undefined-function-apache-request-headers
            if( !function_exists('apache_request_headers') ) {
                function apache_request_headers() {
                  $arh = array();
                  $rx_http = '/\AHTTP_/';
                  foreach($_SERVER as $key => $val) {
                    if( preg_match($rx_http, $key) ) {
                      $arh_key = preg_replace($rx_http, '', $key);
                      $rx_matches = array();
                      // do some nasty string manipulations to restore the original letter case
                      // this should work in most cases
                      $rx_matches = explode('_', $arh_key);
                      if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
                        foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
                        $arh_key = implode('-', $rx_matches);
                      }
                      $arh[$arh_key] = $val;
                    }
                  }
                  return( $arh );
                }
            }
            $headers   = apache_request_headers();
            $context   = array();

            $context[] = 'Host: '.$this->host.':'.$this->port;
            $context[] = 'X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'];
            $context[] = 'X-Forwarded-Host: '.$_SERVER['HTTP_HOST'];
            $context[] = 'X-Forwarded-Server: '.$_SERVER['SERVER_NAME'];

            foreach($headers as $key=>$value)
            {
                if(strtolower($key) != 'host')
                {
                    $context[] = $key.': '.$value;
                }
            }

            $command = curl_init();
            curl_setopt( $command, CURLOPT_HTTPHEADER, $context);
            curl_setopt( $command, CURLOPT_URL, "http://".$this->host.':'.$this->port.$uri);
            curl_setopt( $command, CURLOPT_BINARYTRANSFER, true );
            curl_setopt( $command, CURLOPT_TIMEOUT, $this->timeout );
            curl_setopt( $command, CURLOPT_HEADERFUNCTION, array($this,'processResponseHeaders'));
            curl_setopt( $command, CURLOPT_WRITEFUNCTION, array($this,'processResponseBody'));
            return $command;
        }

        /**
         * Process the response body
         *
         * @param cURL $command reference to the curl command used to generate this response
         * @param string $data the response body
         * @return void
         * @author Adam Venturella
         */
        private function processResponseBody(&$command, $data)
        {
            $bytes = strlen($data);
            echo $data;
            return $bytes;
        }

        /**
         * Process the response headers
         *
         * @param cURL $command reference to the curl command used to generate this response
         * @param string $header current header in the response
         * @return void
         * @author Adam Venturella
         */
        private function processResponseHeaders(&$command, $header)
        {
            $bytes = strlen($header);

            // cURL handles chunked decoding for us, so a response from 
            // this proxy will never be chunked

            if ($header !== "\r\n" && strpos($header, 'chunked') === false)
            {
                header(rtrim($header));
            }

            return $bytes;
        }
    }
    ?>

我已經參加了好幾天,但似乎無法使其正常工作,因此我將其扔掉以尋求幫助,以使php代理腳本正確無誤,或幫助確定其他方法。

我猜想復制(例如_changes提要)使用帶有分塊傳輸編碼的長壽命請求,而您的PHP代理對此並不很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM