我正在使用 PHP(Codeigniter)开发 REST API,并尝试为 API 访问实现 oauth 2-legged 身份验证。将使用开发人员在将我们的 API 与网站或移动应用程序集成时在编码中使用的一对凭据访问 API(因此没有最终用户授权网站或移动应用程序)。
到目前为止,我实施的看起来像是 0-legged。我只是使用消费者秘密和空访问令牌对请求进行 oauth 签名(HMAC_SHA1)。但是根据我在其他地方读到的一些答案,签署请求并验证签名是 oauth 2-leg 实施所需要做的一切(参见https://www.quora.com/What-are-the-specific -两腿和三腿OAuth提供者实现之间的差异)
这是我目前拥有的 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 中).. controllers/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,我想知道,如果我当前的实现是 2-legged 吗?如果不是,对于我的场景来说,两条腿肯定是一种更安全的方式吗?
非常感谢任何帮助。