【问题标题】:twitter oauth request token failstwitter oauth 请求令牌失败
【发布时间】:2013-10-22 03:51:58
【问题描述】:

我尝试实现“使用 Twitter 登录”
我在这里看到了很多关于这个主题的问题,我已经阅读了很多并且完全卡住了
我使用了以下链接:

implementing Sign in with Twitter
POST oauth/request_token
Creating a signature
Authorizing a request

结果是
response : Failed to validate oauth signature and token(可能是最常见的错误 =))

我做了什么:

date_default_timezone_set('UTC');
$oauth_consumer_key = 'mYOauThConsuMerKey'; //from app settings

function generate_nonce() {
    $mt = microtime();
    $rand = mt_rand();
    return md5($mt . $rand); // md5s look nicer than numbers
}
$oauth_nonce = generate_nonce();
    $http_method = 'POST';
    $base_url = 'https://api.twitter.com/oauth/request_token';
    $oauth_signature_method = 'HMAC-SHA1';
    $oauth_timestamp = time();
    $oauth_token = 'mytokenFromAPPsettoings';
    $oauth_version = '1.0';
$oauth_callback = 'http://twoends.home/backend';
    $params = array(
        rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
        rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
        rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
        rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
        rawurlencode('oauth_token')=>rawurlencode($oauth_token),
        rawurlencode('oauth_version')=>rawurlencode($oauth_version),
    );

    ksort($params);
    $parameter_string = http_build_query($params,'','&');
        $base_string  = strtoupper($http_method).'&';
        $base_string .= rawurlencode($base_url).'&';
        $base_string .= rawurlencode($parameter_string);

        $oauth_consumer_secret = 'myappconsumersecret';
        $oauth_token_secret = 'mytokensecret';
$oauth_signing_key =rawurlencode($oauth_consumer_secret).'&'.rawurlencode($oauth_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_string, $oauth_signing_key, true));
$DST ='OAuth ';
foreach($params as $key=>$value){
    $DST .= $key.'='.'"'.$value.'"&';
}
$DST = rtrim($DST,'&');

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$DST));
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);

所以,这段代码很费劲,它仍然会产生错误
在一个主题中,我读过这个阶段不需要令牌:有或没有 - 没有关系 - 仍然是同样的错误
试图玩弄时间(设置 UTC)-同样的错误
我也尝试使用某人的工作代码,例如this,但这对我不起作用
为什么我不使用某人的 lib - 因为我想逐步完成算法,但我已经厌倦了,需要帮助

提前谢谢,感谢任何帮助,可以得到一个工作分步指南的例子吗?

【问题讨论】:

    标签: php curl twitter twitter-oauth


    【解决方案1】:

    您的代码似乎有几处错误:

    1) 你的 params 数组应该包含 oauth_consumer_key 而不是 oauth_token

    $params = array(
        rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
        rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
        rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
        rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
        rawurlencode('oauth_consumer_key')=>rawurlencode($oauth_consumer_key),
        rawurlencode('oauth_version')=>rawurlencode($oauth_version),
    );
    

    2) 请求令牌的签名密钥应使用 oauth_consumer_secret 后跟 & 符号:

    $oauth_signing_key =rawurlencode($oauth_consumer_secret).'&';

    3) 您似乎没有在 Authorization 标头中的任何位置设置签名。做:

    $DST ='OAuth ';
    foreach($params as $key=>$value){
        $DST .= $key.'='.'"'.$value.'"&';
    }
    $DST .= 'oauth_signature='.rawurlencode($oauth_signature)
    

    【讨论】:

    • 1 - 我的错误,它存在,oauth_token 也在那里 - 我放弃了它。 2 - 用您的替换签名密钥。 3 - 将签名添加到 $params $params['oauth_signature'] = rawurlencode($oauth_signature)。结果:[request_header] => GET /oauth/request_token HTTP/1.1 Host: api.twitter.com Accept: */* Authorization: OAuth oauth_callback="http%3A%2F%2Ftwoends.home%2Fbackend"&oauth_consumer_key="consumer_key"&oauth_nonce="45ed597e5456715d6880cf73d702a7df"&oauth_signature="5ap7idjtbcdlBAeAx3HSVQpLqBk%3D"&oauth_signature_method="HMAC-SHA1"&oauth_timestamp="1381843238"&oauth_version="1.0" 仍然失败
    • 正如我写的答案 - 看到标头通过 GET 请求发送,添加选项 curl_setopt($ch, CURLOPT_POST, true); 现在我收到 http 错误 - 400,但没有收到 - “无法验证 oauth 签名和令牌“
    • 我想我看到了问题所在。在 Authorization 标头中,参数应该用逗号和空格而不是 & 号分隔。 ($DST .= $key.'='.'"'.$value.'", ';)
    • 你说得对,我修复了它,现在我得到了标题:` [request_header] => POST /oauth/request_token HTTP/1.1 主机:api.twitter.com 接受:/ 授权:OAuth oauth_callback="http%3A%2F%2Ftwoends.home%2Fbackend", oauth_consumer_key="encoded_consumer_key", oauth_nonce="0cd119c053e5787ca77d8589d59975d1", oauth_signature="WeAeM%2FR1SQZbwlg0zR_sign , oauth_timestamp="1381907960", oauth_version="1.0" Content-Length: -1 Content-Type: application/x-www-form-urlencoded Expect: 100-continue`, 仍然 err 400 - Bad request
    • 所以,我得到两个错误:如果curl_setopt($ch, CURLOPT_POST, true);,则为 400,如果没有,则为 401。如果我查看POST oauth/request_token - 它同时接受 GET 或 POST,我无法想象为什么会有如此大的差异
    【解决方案2】:

    看起来 oauth_callback url 在 basestring 中进行了三重编码。它应该是以下形式:

    POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&
    oauth_callback%3Dhttp%253A%252F%252Ftwoends.home%252Fbackend%26
    oauth_consumer_key%3Dapp_cons_keyQjQ7u5lgwA ...
    

    在你的基本字符串中:

    oauth_callback%3Dhttp%25253A%25252F%25252Ftwoends.home%25252Fbackend
    

    罪魁祸首似乎是“http_build_query”。

    【讨论】:

    • 感谢您的建议,我使用了新的 API 和 oauth2,它可以工作了!我想这就是原因,感谢提琴手 - 很酷=)
    • 如果您只想代表您的应用程序发出请求,则 oauth2 不记名令牌很好。如果您希望能够代表其他用户执行操作,您仍然需要使用 oauth 1.0a。
    • 排除“http_build_query”:$params = array( 'oauth_consumer_key'=>$oauth_consumer_key, 'oauth_nonce'=>$oauth_nonce, 'oauth_callback'=>$oauth_callback, 'oauth_signature_method'=>$oauth_signature_method, 'oauth_timestamp'=>$oauth_timestamp, 'oauth_version'=>$oauth_version, ); $parameter_string = ''; foreach($params as $key=>$param){ $parameter_string .= rawurlencode($key).'&'.rawurlencode($param); } $parameter_string = rtrim($parameter_string,'&');
    • 还是很糟糕。我继续挖掘它=)
    • 不应该是:$parameter_string .= rawurlencode($key).'='.rawurlencode($param).'&';
    【解决方案3】:

    我想重新审视一个问题并发布新数据
    感谢@Jonny S,我发现了一些错误并得到了另一个错误 =)

    所以,我的工作流程现在看起来:

    生成随机数的函数,附加信息:oauth_nonce in api, oauth.net

    function generate_nonce() {
        $mt = microtime();
        $rand = mt_rand();
    
        return md5($mt . $rand); // md5s look nicer than numbers
    }
    

    Implementing Sign in with Twitter(这个链接向我们展示了我们应该提前发布的标题)并向我们展示了移动的方向 - POST oauth/request_token
    此页面链接oauth docs section 6.1
    在那里我们可以找到请求令牌所需的参数,但在官方文档中你不会找到“oauth_calback”参数,这是 twitter API 中的必需参数!

    我要做的下一步 - 收集所需的参数:

    • oauth_consumer_key

      $oauth_consumer_key = 'YoUrS KEy FrOm aPP ApI';
      
    • oauth_nonce

      $oauth_nonce = generate_nonce();
      
    • oauth_callback

      $oauth_callback = 'http://twoends.home/backend';
      
    • oauth_sinature_method

      $oauth_signature_method = 'HMAC-SHA1';
      
    • oauth_timestamp

      $oauth_timestamp = time();
      
    • oauth_version

      $oauth_version = '1.0';
      
    • 附加参数(过程中需要):

    • OAuth 签名(最棘手的部分)

    这里有一个关于如何操作的 API 页面Creating a signature

    首先我们需要收集所有需要的参数,百分比编码和排序,我将它们推送到数组:

        $params = array(
            rawurlencode('oauth_consumer_key')=>rawurlencode($oauth_consumer_key),
            rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
            rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
            rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
            rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
            rawurlencode('oauth_version')=>rawurlencode($oauth_version),
        );
    

    然后排序:

        ksort($params);
    

    然后我正在创建参数字符串:

        $parameter_string = http_build_query($params,'','&');
    

    结果:

    PARAM字符串:oauth_callback = HTTP%253A%252F%252Ftwoends.home%252Fbackend&oauth_consumer_key = oauth_consumer_key_wQjQ7u5lgwA&oauth_nonce = 46fa649c21ac5315d4d4510ff68ad630&oauth_signature_method = HMAC-SHA1&oauth_timestamp = 1381930918&oauth_version = 1.0 P>

    接下来我需要创建 base_string,它将用于创建签名作为 hash_hmac() 函数的数据参数

        $base_string = strtoupper($http_method).'&';
        $base_string .= rawurlencode($base_url).'&';
        $base_string .= rawurlencode($parameter_string);
    

    结果:

    POST&HTTPS%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%25253A%25252F%25252Ftwoends.home%25252Fbackend%26oauth_consumer_key%3Dapp_cons_keyQjQ7u5lgwA%26oauth_nonce%3D46fa649c21ac5315d4d4510ff68ad630%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1381930918%26oauth_version %3D1.0

    接下来我从 APP 设置中获取 consumer_secret 以创建签名密钥,该密钥将用于在 hash_hmac() 函数中创建签名作为第三个参数

        $oauth_consumer_secret = 'consumer_secret_from_app_settings';
        $oauth_signing_key = rawurlencode($oauth_consumer_secret).'&';
    

    提一提:第一步(request_token 我们不需要放置任何令牌)

    这一步创建签名:

        $oauth_signature = base64_encode(hash_hmac('sha1', $base_string, $oauth_signing_key, true));
    

    现在我们需要向 params 数组添加签名并构建标题字符串

        $params['oauth_signature'] = rawurlencode($oauth_signature);
        ksort($params);
    

    建筑标头字符串可以在Building the header string找到

        $DST ='OAuth ';
        foreach($params as $key=>$value){
            $DST .= $key.'='.'"'.$value.'", ';
        }
        $DST = rtrim($DST,', ');
    
        //or we can make it by hand as below
    
        //$DST .= 'oauth_nonce="'.rawurlencode($oauth_nonce)
        //     .'", oauth_callback="'.rawurlencode($oauth_callback)
        //     .'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="'
        //     .rawurlencode($oauth_timestamp).'", oauth_consumer_key="'
        //     .rawurlencode($oauth_consumer_key).'", oauth_signature="'
        //     .rawurlencode($oauth_signature).'", oauth_version="1.0"';
    

    最后一步(我希望)是发送请求:

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $base_url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$DST));
        curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    
        $response = curl_exec($ch);
        $info = curl_getinfo($ch);
        curl_close($ch);
    
        echo '<pre>';
            print_r($info);
        echo '</pre>';
    

    此代码产生错误 400 - 错误请求
    如果我删除 curl_setopt($ch, CURLOPT_POST, true);我收到错误 - 401
    请求信息转储:

    Array
    (
        [url] => https://api.twitter.com/oauth/request_token
        [content_type] => 
        [http_code] => 400
        [header_size] => 66
        [request_size] => 471
        [filetime] => -1
        [ssl_verify_result] => 0
        [redirect_count] => 0
        [total_time] => 0.710993
        [namelookup_time] => 0.081279
        [connect_time] => 0.23482
        [pretransfer_time] => 0.550913
        [size_upload] => 0
        [size_download] => 0
        [speed_download] => 0
        [speed_upload] => 0
        [download_content_length] => 0
        [upload_content_length] => -1
        [starttransfer_time] => 0.710976
        [redirect_time] => 0
        [redirect_url] => 
        [primary_ip] => 199.16.156.104
        [certinfo] => Array
        (
        )
    
        [primary_port] => 443
        [local_ip] => 192.168.1.234
        [local_port] => 54994
        [request_header] => POST /oauth/request_token HTTP/1.1
    Host: api.twitter.com
    Accept: */*
    Authorization: OAuth oauth_callback="http%3A%2F%2Ftwoends.home%2Fbackend", oauth_consumer_key="your_consumer_keyCwQjQ7u5lgwA", oauth_nonce="1ba83f0af239f439c1524096c33faefe", oauth_signature="QZZvrJ8wzCQOYhiKJeT4vz%2FWCcg%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1381931941", oauth_version="1.0"
    Content-Length: -1
    Content-Type: application/x-www-form-urlencoded
    Expect: 100-continue
    
    
    )
    

    希望这将有助于了解在哪里找到错误,提前我也会尝试使用 Fiddler 来跟踪请求

    ---------------------------------------
    通过使用新的 API 解决

    【讨论】:

    • 使用了新的 API POST oauth2/token,我花了几分钟才让它工作,我想它应该在旧 API 中注意到它的有用性
    • 如果您只想代表您的应用程序发出请求,则 oauth2 不记名令牌很好。如果您希望能够代表其他用户执行操作,您仍然需要使用 oauth 1.0a。
    猜你喜欢
    • 1970-01-01
    • 2014-10-08
    • 2017-06-23
    • 2012-06-22
    • 2012-08-13
    • 2011-09-05
    • 2017-01-10
    • 2013-12-01
    • 2019-09-16
    相关资源
    最近更新 更多