如何通过 jQuery AJAX 从使用 OAuth 1.0 身份验证的 Upwork API 请求 JSONP 文件?

Posted

技术标签:

【中文标题】如何通过 jQuery AJAX 从使用 OAuth 1.0 身份验证的 Upwork API 请求 JSONP 文件?【英文标题】:How to request a JSONP file via jQuery AJAX from the Upwork API that uses OAuth 1.0 authentication? 【发布时间】:2016-05-26 07:01:45 【问题描述】:

我需要通过 jQuery AJAX 从Upwork API 请求一个 JSONP 文件。 Upwork API 使用 OAuth 1.0 身份验证。

我是 Oauth 的新手,但最近几天一直在阅读它,我大致了解它的工作原理,但在这个特定的场景/环境中实施它非常困难。几天来一直在敲我的脑袋,Upwork API 支持并没有太大帮助:(

我需要通过 OAuth 1.0 中的所有必要步骤并获取随请求 url 传递的 OAuth 参数。请帮忙!

这是我到目前为止所做的:

// My Upwork API key and secret
var api_key = 'xxx',
    api_secret = 'xxx';


// TO-DO
// OAuth 1.0 authentication


// TO-DO
// required oauth parameters
// https://developers.upwork.com/?lang=node#authentication_required-oauth-10-parameters
var oauth_consumer_key = '',
    oauth_signature = '',
    oauth_nonce = '',
    oauth_signature_method = '',
    oauth_timestamp = '',
    oauth_token = '';


// Compose request url with required oauth parameters
var url  = "https://www.upwork.com/api/profiles/v2/search/jobs.json?q=java&callback=?";
url += "&oauth_consumer_key="+oauth_consumer_key;
url += "&oauth_signature="+oauth_signature;
url += "&oauth_nonce="+oauth_nonce;
url += "&oauth_signature_method="+oauth_signature_method;
url += "&oauth_timestamp="+oauth_timestamp;
url += "&oauth_token="+oauth_token;


// Ajax request
// https://developers.upwork.com/?lang=node#getting-started_cross-domain-requests
$.ajax(
  url: url,
  dataType: 'JSONP',
  success:function(json)
    alert("Success: "+json.server_time);
  ,
  error:function()
    alert("Error");
  ,
);

代码笔:http://codepen.io/nunoarruda/pen/xZBEzB?editors=1010

提前致谢!

【问题讨论】:

你能分享你的服务器详细信息(URL)吗? 为什么不使用像github.com/ddo/oauth-1.0a这样的库 @saravanakumar 如果您要求从 API 获取 URL 以执行 Oauth 过程的所有请求,您可以在文档 developers.upwork.com/?lang=node#authentication_oauth-10 中找到它们 @Benvorth 我已经尝试了几次,但无法成功。此外,看起来该框架仅处理 Oauth 过程的一部分,即您已经拥有令牌密钥和令牌秘密的部分。 OAuth 不仅仅是传递用户名/密码之类的身份验证参数 - 还有更多功能,这就是为什么建议您使用其他可以为您完成必要工作的谎言(请参阅 oauthbible.com for有关身份验证过程如何工作的更多信息) 【参考方案1】:

TLDR 我从 OAuth 1.0 流程描述开始,以确保下面的代码示例和我的结论清楚。 如果 OAuth 过程清楚,请跳到 The code 部分。

OAuth 1.0 流程

我使用以下术语(它们与官方术语不同,但希望能让事情更清楚):

应用 - 您的应用 服务 - 您请求数据的服务 用户 - 允许您访问其服务存储的数据的用户

准备。在服务中注册您的应用程序

您将获得用于启动 Oauth 过程的客户端密钥和秘密。

对于 Upwork,您可以在此处执行此操作 - https://www.upwork.com/services/api/apply。

第 1 步。获取临时 oauth 令牌。

此请求由您的应用向服务发出。 您的应用通过了client key,因此服务知道谁在询问。

请求是使用client secret 签名的,服务也有它,并且可以验证它是否真的是来自您的应用程序的请求,而不是来自窃取您客户端密钥的其他人(这就是为什么您不应该向任何人展示你的秘密)。

服务器返回temporary oauth token + temporary oauth secret

如果是 Upwork,请将此请求发送至 https://www.upwork.com/api/auth/v1/oauth/token/request

第 2 步。请求用户授予您访问权限。

您的应用程序只是将用户重定向到 Service 提供的特殊 URL。

该服务显示一个对话框,用户可以在其中为您的应用程序提供访问权限。 这个特殊的 URL 包括步骤 1 中的temporary token,因此服务知道哪个应用程序请求访问。

如果您有一个网络应用程序,您只需在浏览器中打开这个特殊的 url。 然后,该服务使用 oauth_callback(将用户重定向回的 URL)重定向回您的应用程序。 该服务还将oauth_verifier 传递给oauth_callback URL。

如果您有桌面应用程序,它应该启动浏览器并且服务可以将oauth_verifier 显示为字符串,因此用户可以手动将其复制并粘贴回您的应用程序。在这种情况下,您将oauth_calback 设置为特殊的oob(带外)值。 这部分(没有重定向返回)在规范中没有严格描述,所以细节取决于服务。 它可能根本不受支持或以其他方式支持。

在 Upwork 的情况下,您将用户发送到 URL https://www.upwork.com/services/api/auth?oauth_token=temporary token

第 3 步。获取真正的 oauth 访问令牌。

您的应用将第 1 步中的临时令牌和第 2 步中的 oauth 验证器发送到服务。 请求再次被签名,但这次使用client secrettemporary token secret。 服务以访问令牌 + 秘密进行响应。

对于 Upwork,URL 是 https://www.upwork.com/api/auth/v1/oauth/token/access

这些是获取真正访问权限并开始使用服务 API 的 3 个步骤。 规范中的例子也很好很清晰,check it。

另请注意,OAuth 1.0 不能在 100% 客户端应用程序中安全使用。 在第 1 步中,您需要使用任何人都不应该知道的私有 client secret(因此您不得将其放入您的客户端代码中)。 在第 2 步中,服务会将浏览器重定向回oauth_callback,您无法在客户端处理它。

从技术上讲,如果您使用没有回调的场景(如桌面应用程序),则可以使用 oauth 客户端。在这种情况下,用户需要手动将验证器复制回您的应用程序。 Servcie 也应该支持这种场景(Upwork 不支持,见下文)。

第 4 步。使用服务 API

现在,一旦您获得访问令牌,您就可以发出 API 请求来获取数据,在这里您可以发送第 3 步中的 client keyaccess token。 请求使用client secret + access token secret 签名。

流程中最复杂的部分是请求签名,规范中有详细介绍,但这是最好使用库的地方。

oauth-1.0a 允许您在 node.js 和客户端 javascript 中签署您的请求。 您仍然需要从您的应用程序中执行 oauth 步骤,该库只会帮助您进行签名。

代码

我从浏览器 javascript 中测试了 Step 1,但 Upwork 不支持这种情况。 如果我使用 ajax 发送常规 POST 请求,它会返回“Access-Control-Allow-Originerror. And if I try this request usingJSONP”,Upwork 会以 404 错误响应。

所以JSONP 不支持api/auth/v1/oauth/token/request 端点。

步骤 1-3 应使用服务器端完成(无论如何客户端身份验证都是不安全的)。

这是令牌请求的外观 (Step 1):

oauthTest.step1_tempToken = function() 
    var request_data = 
        url: 'https://www.upwork.com/api/auth/v1/oauth/token/request',
        method: 'POST',
        data: 
    ;
    request(
        url: request_data.url,
        method: request_data.method,
        form: oauthTest.oauth.authorize(request_data) // no token yet
    , function(error, response, body) 
        var data = qs.parse(body);
        console.log(data);
    );
;

完整代码为here。

请注意,Upwork 有 nodejs library,但我并没有使用它来手动完成所有操作。 请求使用oauth-1.0a签名。

Step 2 是在浏览器中执行的,在这里您只需打开 'https://www.upwork.com/services/api/auth?oauth_token=xxx' 之类的 url 并获取 oauth 验证器。 在实际场景中,您的应用程序将指定oauth_callback 参数,Upwork 将向您的应用程序发送 oauth 验证器。 在此示例中,我只是从浏览器手动复制它并传递到下一步。

拥有 oauth 验证器,您可以获得永久访问令牌 (Step 3):

oauthTest.step3_accessToken = function(oauth_verifier) 
    var request_data = 
        url: 'https://www.upwork.com/api/auth/v1/oauth/token/access',
        method: 'POST',
        data: 
          oauth_verifier: oauth_verifier
        
    ;
    request(
        url: request_data.url,
        method: request_data.method,
        form: oauthTest.oauth.authorize(request_data, oauthTest.tempToken) // use the temp token
    , function(error, response, body) 
        var data = qs.parse(body);
        console.log(data);
    );
;

最后,您可以使用 API,Step 4(同样,这是服务器端代码):

oauthTest.queryAPI = function() 
    var request_data = 
        url: 'https://www.upwork.com/api/profiles/v2/search/jobs.json',
        method: 'GET',
        data: 
          'q': 'java'
        
    ;
    request(
        url: request_data.url,
        method: request_data.method,
        qs: oauthTest.oauth.authorize(request_data, oauthTest.accessToken) // use the access token
    , function(error, response, body) 
        console.log(body);
    );
;

可以从客户端使用 API(虽然不好,因为您需要将访问令牌和密码放入代码中)。

解决方案很棘手,因为文档 (https://developers.upwork.com/?lang=node#getting-started_cross-domain-requests) 不完整且不完全正确。

它说要在请求中添加callback=?,但是当你设置JSONP数据类型时,jQuery会自动添加这个参数。参数值也设置为一些随机字符串,所以我认为这个参数不应该被签名,但它似乎应该:

function queryAPI(public, secret) 
    var accessToken = 
        public: public,
        secret: secret
    
    var request_data = 
        url: 'https://www.upwork.com/api/profiles/v2/search/jobs.json',
        method: 'GET',
        data: 
          'q': 'java',
          'callback': 'jsoncallback'
        
    ;

    // It looks like a bug on the Upwork side, the `callback` parameter is usually
    // selected randomly by jQuery, so server side should skip it from the signature
    // validation, but it doesn't, so we sign the request with `callback` parameter
    // and then remove it from data, because it this parameter is automatically added
    // by jQuery, we also set the static value for callback - 'jsoncallback`
    var data = oauth.authorize(request_data, accessToken);
    delete data.callback;

    // Ajax request
    // https://developers.upwork.com/?lang=node#getting-started_cross-domain-requests
    $.ajax(
      // url: url,
      url: request_data.url,
      dataType: 'JSONP',
      jsonpCallback: 'jsoncallback',
      // here the data will contain 'q=java' as well as all the oauth parameters
      // the request type will be GET (since this is JSONP), so all parameters will
      // be converted to the query string
      // you can check the URL in the developer console, in the list of network requests
      //data: oauth.authorize(request_data, accessToken),
      data: data,
      cache: true, // this removes the '_' parameter
      success:function(json)
        console.log(json);
      ,
      error: function(error)
        console.log(error);
      ,
    );
;

无论如何这是不安全的,并且由于您需要服务器端进行 Oauth,您也可以使用它向 API 发出 API 请求并将结果返回给客户端。

如何使用代码示例

获取 nodejs-upwork-oauth 文件夹的副本,执行npm install 并启动 node.js 控制台:

$ node
> oauthTest = require('./server')
> oauthTest.step1_tempToken()
> // wait for the result
 public: 'xxxx',
  secret: 'yyyy' 
> // copy the public temp access token
> // don't exit it yet
>

现在在浏览器中打开test.html并打开JS控制台,运行:

> step2_askUser('temp_access_token_here')
> // it will open the upwork auth page in new tab
Application authorized

jobs-alert has been authorized.
Your oauth_verifier=zzzz

You can close this window and return to your application.
> // authorize there and copy the oauth_verifier

回到nodejs控制台:

> oauthTest.step3_accessToken('oauth verifier here')
> // wait for the result
 public: 'nnnnn',
  secret: 'kkkkk' 
> oauthTest.queryAPI()
> // see the query result

然后返回浏览器:

> queryAPI('access token public', 'access token secret')
< Object server_time: 1456301893, auth_user: Object, profile_access: "public,odesk", jobs: Array[10], paging: Object

【讨论】:

使用有效的客户端请求更新了答案。

以上是关于如何通过 jQuery AJAX 从使用 OAuth 1.0 身份验证的 Upwork API 请求 JSONP 文件?的主要内容,如果未能解决你的问题,请参考以下文章

PHP-AJAX:如何通过 php/json 数组从查询中填充 jquery 数据表

如何实现一个 jquery ajax 表单,它通过 php 请求从 web api 请求信息?

如何使用多个 Django FBV 通过 Ajax+jQuery 捕获和保存数据

如何通过 jQuery AJAX 从使用 OAuth 1.0 身份验证的 Upwork API 请求 JSONP 文件?

如何通过 AJAX 将 jquery 对象数据发送到 php?

如何使用 jQuery Ajax 调用从 ASP.NET Web Api 下载 CSV 文件