Я работаю над REST API в PHP (Codeigniter) и пытаюсь реализовать двухстороннюю аутентификацию oauth для доступа к API. Доступ к API должен осуществляться с использованием пары учетных данных, которые разработчик будет использовать в коде при интеграции нашего API с веб-сайтом или мобильным приложением (поэтому конечный пользователь не авторизует веб-сайт или мобильное приложение).
То, что я реализовал до сих пор, выглядит как 0-ножка. Я просто подписываю (HMAC_SHA1) запрос, используя секрет клиента и пустой маркер доступа. Но согласно некоторым ответам, которые я читал в другом месте, подписание запроса и проверка подписи — это все, что нужно сделать для реализации oauth 2-leg. https://www.quora.com/What-are-the-specific-differences-between-a-two-legged-and-three-legged-OAuth-provider-implementation )
Вот клиентская часть реализации в PHP, которая у меня есть на данный момент;
<?php
// Just a demo for the client side implementation of oauth signed requests.
require_once ("oauth/oauth.php"); // Google oauth library
function send_request($method = '', $api_endpoint = '',$request_params = array()){
$consumer = new OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
$sig_method = new OAuthSignatureMethod_HMAC_SHA1;
//use oauth lib to sign request
$req = OAuthRequest::from_consumer_and_token($consumer, null, $method, $api_endpoint, $request_params);
$sig_method = new OAuthSignatureMethod_HMAC_SHA1();
$req->sign_request($sig_method, $consumer, null);//note: double entry of token
if($method == 'GET'){
echo "<br />".$req->to_url();
$ch = curl_init($req->to_url());
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result = curl_exec($ch);
$curl_info = curl_getinfo($ch);
//print_r($curl_info);
$error = curl_error($ch);
//print_r($error);
curl_close($ch);
return $result;
}elseif($method == 'POST'){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$api_endpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HEADER,'Content-Type: application/x-www-form-urlencoded');
//echo "<br />".$req->to_url();
//echo "<br />Post data: ".$req->to_postdata();
//curl_setopt($ch, CURLOPT_POSTFIELDS, $req->to_postdata());
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request_params));
$result = curl_exec($ch);
$curl_info = curl_getinfo($ch);
print_r($curl_info);
$error = curl_error($ch);
//print_r($error);
curl_close($ch);
return $result;
}
}
// API consumer key and secret
define('CONSUMER_KEY', 'd4hkilp1z0pqj7158y0j');
define('CONSUMER_SECRET', 'rqhzan3mdx7wov3gvh4u');
// Authorize
// Get products from odw api
$api_endpoint = 'http://testgapi.local/api/product/search'; // search/format/json , search/format/xml
$request_params = array();
$request_params['category_type'] = 'Tour';
$request_params['location'] = 'Las Vegas';
$request_params['start_date'] = '09/22/2015';
$request_params['end_date'] = '12/31/2015';
$result = send_request('GET', $api_endpoint, $request_params); // Call REST service with GET method
//$result = send_request('POST', $api_endpoint, $request_params);
print_r($result);
//echo $result;
?>
Проверка запроса на стороне сервера (в Codeigniter).
Контроллеры / API / product.php;
<?php
defined('BASEPATH') or exit('No direct script access allowed');
require APPPATH . '/libraries/REST_Controller.php';
class Product extends REST_Controller
{
var $valid_request;
function __construct()
{
// Construct the parent class
parent::__construct();
$this->load->library('Oauth_server');
}
public function search_get()
{
$this->valid_request = $this->oauth_server->validate_request();
if (!$this->valid_request)
{
$response = array(
'status' => "Failed",
'error_message' => "Access Denied.",
);
return $this->response($response, 201); // NO_CONTENT (204) being the HTTP response code
} else
{
// Do something
}
}
} // End of class
?>
библиотеки / Oauth_server.php;
<?php
require_once (APPPATH . "libraries/oauth/oauth.php"); // Google oauth library
class Oauth_server {
var $CI;
function __construct(){
// Nothing to do yet.
$this->CI = &get_instance();
}
function validate_request(){
//echo "<br />".
$consumer_key = !empty($_REQUEST['oauth_consumer_key'])? $_REQUEST['oauth_consumer_key'] : "";
// Use the oauth_consumer_key in the client request to find the secret in our system.
$secret = $this->get_consumer_secret($consumer_key);
$consumer = new OAuthConsumer($consumer_key, $secret);
$sig_method = new OAuthSignatureMethod_HMAC_SHA1;
//echo "<br />Method: ".
$method = $_SERVER['REQUEST_METHOD'];
//echo "<br />URI: ".
$uri = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
$sig = $_REQUEST['oauth_signature'];
$req = new OAuthRequest($method, $uri);
//token is null because we're doing 2-leg
return $sig_method->check_signature( $req, $consumer, null, $sig );
}
function get_consumer_secret($consumer_key){
// Fetch the associated consumer secret from the db using the consumer key.
$query = $this->CI->db->query("SELECT consumer_secret FROM gapi_users WHERE consumer_key = ?", array($consumer_key));
$result = $query->row_array();
if(!empty($result)){
return $result['consumer_secret'];
}
else{
return false;
}
}
}
?>
Я мог бы также заставить запрос быть выполнен через https для дополнительной безопасности.
Предполагая, что я придерживаюсь oauth, я хотел бы знать, является ли моя текущая реализация вообще двухсторонней? Если это не так, будет ли двухногая, безусловно, более безопасным способом для моего сценария?
Буду очень признателен за любую помощь.
Задача ещё не решена.
Других решений пока нет …