无法使用Twitter V1.1 API对用户进行身份验证

如何解决无法使用Twitter V1.1 API对用户进行身份验证

我已经实现了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标头。这是一个函数,它使用上面的辅助函数(以及其他一些返回所需信息的函数):

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_signature'        => $signature,'oauth_signature_method' => 'HMAC-SHA1','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,$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标头中所有内容的顺序。我已经遍历了我的每个小助手函数十多次,以确保它们接受正确的参数并输出适当的值。我什至用文档中的OAuth凭据替换了自己的OAuth凭据,并最终获得了与它们对签名密钥,签名等相同的结果:

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

这看起来不错,现在我使用签名密钥: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帐户可以测试所有这些内容,但是他们的文档具有我可以使用的示例密钥和示例输出,并使用这些更改和文档产生了相同的输出。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-