php - 无法使用 Twitter V1.1 API 验证用户

标签 php twitter oauth twitter-oauth

我已经通过 Creating a Signature 实现了所有内容。我创建了一个函数来收集所需的参数(为了清楚起见,我在此处添加了一些注释):

function collect_parameters(){
    global $credentials; // This is an Object with my App's credentials and stuff

    $oAuth = get_user_oauth();  // This returns an object with the the personal user OAuth tokens retrieved from the earlier docs.
    $encoded_collection = array();

    $collection = array(
        'status'                 => rawurlencode( $_GET['tweet'] ),
        'include_entities'       => 'true',
        'oauth_consumer_key'     => $credentials->key,
        'oauth_nonce'            => $credentials->nonce, // md5( str_shuffle( uniqid() . mt_rand(0,9999999999) ) )
        'oauth_signature_method' => 'HMAC-SHA1',
        'oauth_timestamp'        => $credentials->time, // current timestamp
        'oauth_token'            => $oAuth->oauth_token,
        'oauth_version'          => '1.0',
    );

    // Percent encode every key and value that will be signed.
    foreach( $collection as $key => $value ){
        $encoded_collection[rawurlencode($key)] = rawurlencode($value); 
    }

    // Sort the list of parameters alphabetically by encoded key.
    ksort( $encoded_collection );

    return http_build_query( $encoded_collection );
}
我使用这个函数来构建签名基本字符串
function create_signature_base_string( $parameter_string, $url = 'https://api.twitter.com/1.1/statuses/update.json', $method = 'POST' ){
    return strtoupper( $method ) .'&'. rawurlencode( $url ) .'&'. rawurlencode( $parameter_string );
}
我用这个函数来计算签名
function calculate_signature( $signature_base_string, $signing_key ){
    return base64_encode( hash_hmac('sha1', $signature_base_string, $signing_key, true) );
}
现在构建 OAuth header 。这是它的一个函数,它使用上面的辅助函数(以及其他一些返回所需信息的函数):
function get_oauth_headers(){
    global $credentials;
    $oAuth = get_user_oauth();
    
    $parameters = collect_parameters();
    $signature_base_string = create_signature_base_string( $parameters );
    $signing_key = get_signing_key();
    $signature = calculate_signature( $signature_base_string, $signing_key );

    $auth_array = array(
        'oauth_consumer_key'     => $credentials->key,
        'oauth_nonce'            => $credentials->nonce,
        'oauth_signature'        => $signature,
        'oauth_signature_method' => 'HMAC-SHA1',
        'oauth_timestamp'        => $credentials->time,
        'oauth_token'            => $oAuth->oauth_token,
        'oauth_version'          => '1.0'
    );

    ksort( $auth_array );

    return $auth_array;
}
现在我已经把所有东西都放在一个漂亮整洁的小数组中,是时候尝试将它发送到 Twitter 了。
function create_tweet( $build_query = true ){
    global $credentials;

    $ch = curl_init();

    $url    = 'https://api.twitter.com/1.1/statuses/update.json';
    $fields = array(
        'status' => rawurlencode( $_GET['tweet'] ) // I've just been using "Test" or "WhyNoWork" style text in this $_GET param
    );

    $oAuth_headers = get_oauth_headers(); // This uses that function above that returns all of the specific parameters for OAuth, sorted, and ready to go.
    $oAuth_array   = array();

    // Loop through the oauth headers, and encode them
    foreach( $oAuth_headers as $key => $value ){
        $oAuth_array[] = rawurlencode($key) .'="'. rawurlencode($value) .'"';
    }

    // Implode it into a single line
    $oAuth_string = implode(', ', $oAuth_array );

    $headers = array(
        'Content-Type: application/x-www-form-rawurlencoded',
        'Authorization: OAuth '. $oAuth_string,
    );

    curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    curl_setopt( $ch, CURLOPT_ENCODING, 'gzip' );
    curl_setopt( $ch, CURLOPT_POST, true );
    
    // It seems to prefer this as a query string instead of postfields?
    if( $build_query == true ){
        curl_setopt( $ch, CURLOPT_URL, $url.'?'.http_build_query($fields) );
    } else {
        curl_setopt( $ch, CURLOPT_URL, $url );
        curl_setopt( $ch, CURLOPT_POSTFIELDS, $fields );
    }

    $result = curl_exec( $ch );
    $info   = curl_getinfo( $ch );

    curl_close( $ch );

    if( isset($_GET['debug']) ){
        echo $result;
        var_dump( $info );
    } else {
        echo $result;
    }
}
例如,这是 OAuth header 中所有内容的顺序。我已经运行了我的每个小助手函数十几次,以确保它们接受正确的参数并输出适当的值。我什至用文档中的凭据替换了我自己的 OAuth 凭据,最终得到的结果与签名 key 、签名等的结果相同:
OAuth Headers
然而,每次我尝试运行 create_tweet() 函数时,都会得到 401 状态代码,错误 32: {"errors":[{"code":32,"message":"Could not authenticate you."}]} 。我到底错过了什么?是否有可能了解为什么他们无法对请求进行身份验证?

这是 collect_parameters() 的输出;include_entities=true&oauth_consumer_key=APP_API_KEY&oauth_nonce=ABC123&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1597456781&oauth_token=USER_AUTH_TOKEN&oauth_version=1.0&status=TESTING这将传递给 Signature Base String 函数,该函数返回以下内容:
POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3DAPP_API_KEY%26oauth_nonce%3DABC123%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1597457034%26oauth_token%3DUSER_AUTH_TOKEN%26oauth_version%3D1.0%26status%3DTESTING
看起来不错,现在我使用签名 key :APP_SECRET&USER_AUTH_SECRET 并传递它们来计算签名给我一个与文档中的值一样的值(并且使用文档中的参数给我他们显示的相同签名):thIsiSeEmSUnNecEssArYPOs3OxQdSNpI=我不明白如何用测试数据替换我的数据并获得相同的结果,但我仍然无法对 API 请求进行身份验证?

最佳答案

您正在执行一些额外的编码。
一、在collect_parameters您正在对 $encoded_collection 的键和值进行编码数组,然后将其传递给 http_build_query 这将进一步编码它们。您可以完全删除循环来编码项目,而是将它们直接传递给 http_build_query .诀窍在于它默认为 +编码,所以你需要告诉它切换到 %使用第四个参数编码:

function collect_parameters()
{
    global $credentials; // This is an Object with my App's credentials and stuff

    $oAuth = get_user_oauth();  // This returns an object with the the personal user OAuth tokens retrieved from the earlier docs.
    
    $collection = [
        'status' => 'Hello Ladies + Gentlemen, a signed OAuth request!',
        'include_entities' => 'true',
        'oauth_consumer_key' => $credentials->key,
        'oauth_nonce' => $credentials->nonce, // md5( str_shuffle( uniqid() . mt_rand(0,9999999999) ) )
        'oauth_signature_method' => 'HMAC-SHA1',
        'oauth_timestamp' => $credentials->time, // current timestamp
        'oauth_token' => $oAuth->oauth_token,
        'oauth_version' => '1.0',
    ];

    // Sort the list of parameters alphabetically by encoded key.
    ksort($collection);

    return http_build_query($collection, '', '&', PHP_QUERY_RFC3986);
}
接下来,在您的 create_tweet函数,在第一个循环中,您再次对不需要并且可以删除的键和值进行编码:
    foreach ($oAuth_headers as $key => $value) {
        $oAuth_array[] = $key . '="' . $value . '"';
    }
不幸的是,我没有 Twitter 帐户来测试所有这些,但他们的文档有我可以使用的示例 key 和示例输出,使用这些更改和文档生成相同的输出。

关于php - 无法使用 Twitter V1.1 API 验证用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63532849/

相关文章:

PHP 粘性表单下拉列表和复选框

c# - 公共(public) API 如何管理负载?

css font twitter like close button,我错过了什么?

java - heroku Java oAuth 与 Salesforce

iphone - 将 OAuth2 添加到 iOS 项目

php - 获取类别中的帖子位置

php - Tumblr API 上传

php - 在 PHP 中使用对 MySQL 的单个 mysqli_fetch_array() 查询填充多个下拉列表

android - 如何在 Android 应用程序中集成 Twitter

android - gmail 通过 oauth SMTPSendFailedException(需要身份验证)