check header Authorization on Restler API framewor

2019-03-22 05:47发布

问题:

I want to extend Restler to check if a valid value of custom header Authorization was passed. I am having trouble in getting around the fix, I tried this, but no chance:

class AuthenticateMe implements iAuthenticate() {

function __isAuthenticated() {
    //return isset($_SERVER['HTTP_AUTH_KEY']) && $_SERVER['HTTP_AUTH_KEY']==AuthenticateMe::KEY ? TRUE : FALSE;
    $headers = apache_request_headers();
    foreach ($headers as $header => $value) {
        if($header == "Authorization") {
            return TRUE;
        } else {
            //return FALSE;
            throw new RestException(404);
        }
    }
}
}

回答1:

Let me quickly fix your custom auth header example

class HeaderAuth implements iAuthenticate{
    function __isAuthenticated(){
        //we are only looking for a custom header called 'Auth'
        //but $_SERVER prepends HTTP_ and makes it all uppercase
        //thats why we need to look for 'HTTP_AUTH' instead
        //also do not use header 'Authorization'. It is not
        //included in PHP's $_SERVER variable
        return isset($_SERVER['HTTP_AUTH']) && $_SERVER['HTTP_AUTH']=='password';
    }
}

I have tested it to make sure it works!

Here is how to make it work with Authorization header, it works only on apache servers

 class Authorization implements iAuthenticate{
    function __isAuthenticated(){
        $headers =  apache_request_headers();
        return isset($headers['Authorization']) && $headers['Authorization']=='password';
    }
}

I figured out that PHP converts Authorization header into $_SERVER['PHP_AUTH_DIGEST'] or $_SERVER['PHP_AUTH_USER'] and $_SERVER['PHP_AUTH_PW'] depending on the type of auth request (digest or basic), we can use the following .htaccess file to enable the $_SERVER['HTTP_AUTHORIZATION'] header

DirectoryIndex index.php

DirectoryIndex index.php
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ index.php [QSA,L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php [QSA,L]
    RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
</IfModule>

important part is RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]

Now our example can be simplified to:

class Authorization implements iAuthenticate{
    function __isAuthenticated(){
        return isset($_SERVER['HTTP_AUTHORIZATION']) && $_SERVER['HTTP_AUTHORIZATION']=='password';
    }
}


回答2:

Header Authentication

there are three ways to do it

  1. HTTP Basic Authentication
  2. HTTP Digest Authentication
  3. Roll our own using custom HTTP headers

You can read more from PHP Manual

Restler 1.0 had a Digest Authentication example. I've modified to make it work with Restler 2.0

class DigestAuthentication implements iAuthenticate
{
    public $realm = 'Restricted API';
    public static $user;
    public $restler;


    public function __isAuthenticated()
    {
        //user => password hardcoded for convenience
        $users = array('admin' => 'mypass', 'guest' => 'guest');
        if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
            header('HTTP/1.1 401 Unauthorized');
            header('WWW-Authenticate: Digest realm="'.$this->realm.'",qop="auth",nonce="'.
            uniqid().'",opaque="'.md5($this->realm).'"');
            throw new RestException(401, 'Digest Authentication Required');
        }

        // analyze the PHP_AUTH_DIGEST variable
        if (!($data = DigestAuthentication::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
        !isset($users[$data['username']]))
        {
            throw new RestException(401, 'Wrong Credentials!');
        }


        // generate the valid response
        $A1 = md5($data['username'] . ':' . $this->realm . ':' . $users[$data['username']]);
        $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
        $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

        if ($data['response'] != $valid_response)
        {
            throw new RestException(401, 'Wrong Credentials!');
        }
        // ok, valid username & password
        DigestAuthentication::$user=$data['username'];
        return true;
    }

    /**
     * Logs user out of the digest authentication by bringing the login dialog again
     * ignore the dialog to logout
     *
     * @url GET /user/login
     * @url GET /user/logout
     */
    public function logout()
    {
        header('HTTP/1.1 401 Unauthorized');
        header('WWW-Authenticate: Digest realm="'.$this->realm.'",qop="auth",nonce="'.
        uniqid().'",opaque="'.md5($this->realm).'"');
        die('Digest Authorisation Required');
    }


    // function to parse the http auth header
    private function http_digest_parse($txt)
    {
        // protect against missing data
        $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
        $data = array();
        $keys = implode('|', array_keys($needed_parts));

        preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);

        foreach ($matches as $m) {
            $data[$m[1]] = $m[3] ? $m[3] : $m[4];
            unset($needed_parts[$m[1]]);
        }

        return $needed_parts ? false : $data;
    }
}


标签: php api rest