Erlang中的OAuth多部分帖子

时间:2014-07-11 06:06:53

标签: twitter oauth erlang

我正在尝试扩展此库https://github.com/tim/erlang-oauth-examples以允许客户端发布多部分帖子(根据Twitter的状态/ update_with_media的需要)。到目前为止,这是我尝试额外的最终签名和身份验证逻辑所必需的。使用边界的身体的形成是在其他地方完成的,我不认为是绊脚石。

oauth_post({multipart, Boundary}, URL, Body, Consumer, Token, TokenSecret) ->
    BodyH   = base64:encode_to_string(crypto:hash(sha, Body)),                                
    Signed  = oauth:sign("POST", URL, [{"oauth_body_hash", BodyH}], Consumer, Token, TokenSecret),
    {[[{ "oauth_signature", Sig}],
      [{"oauth_body_hash", BBody}]], Rest} = 
        proplists:split(Signed, ["oauth_signature", "oauth_body_hash"]),                
    Encoded = [ {"oauth_signature", oauth:uri_encode(Sig)} 
              , {"oauth_body_hash", oauth:uri_encode(BBody)}
              | Rest],
    Sorted  = lists:sort(Encoded),
    Auth    = lists:flatten(string:join([ K++"=\""++V++"\"" || {K,V} <- Sorted], ", ")),      
    OAuth   = "OAuth " ++ Auth,
    ContentType = "multipart/form-data;boundary=" ++ Boundary,                                
    Headers = [ {"Authorization", OAuth}
              , {"Content-Type", ContentType}
              , {"Content-Length", integer_to_list(length(Body))}],                           
    Request = {URL, Headers, ContentType, Body},                                              
    httpc:request(post, Request, [], []).

但到目前为止,此方法调用无法进行身份验证。任何人,有这个领域的专业知识,看到我做错了什么?非常感谢。

答案后

Per Paul的回答如下,这就是我最终使用的内容。更新了我的图书馆的分支。

oauth_post({multipart, Boundary}, URL, Body, Consumer, Token, TokenSecret) ->
    BodyH   = base64:encode_to_string(crypto:hash(sha, Body)),
    Signed  = oauth:sign("POST", URL, [{"oauth_body_hash", BodyH}]
                  , Consumer, Token, TokenSecret),
    {AuthorizationParams, []} = 
        lists:partition(fun({K, _}) -> lists:prefix("oauth_", K) end, Signed),
    Headers = [ oauth:header(AuthorizationParams)],
    ContentType = "multipart/form-data;boundary=" ++ Boundary,
    Request = {URL, Headers, ContentType, Body},
    httpc:request(post, Request, [], []).

1 个答案:

答案 0 :(得分:1)

问题是您的代码仅对签名和正文哈希值进行URI编码。所有oauth_*参数都必须经过URI编码,尤其是oauth_nonce,这是OAuth library中的Base64字符串。

Nonce = base64:encode_to_string(crypto:rand_bytes(32)), % cf. ruby-oauth

作为旁注:

  • 获取键"oauth_body_hash"的值没有意义,因为您首先传递了此值(它位于BodyH)。
  • 您无需对签名中的oauth_参数进行排序。
  • 您不需要Content-TypeContent-Length标头,除非您通过headers_as_is选项,否则httpc会为您添加它们。

简单地说:

oauth_post({multipart, Boundary}, URL, Body, Consumer, Token, TokenSecret) ->
    BodyH   = base64:encode_to_string(crypto:hash(sha, Body)),                                
    Signed  = oauth:sign("POST", URL, [{"oauth_body_hash", BodyH}], Consumer, Token, TokenSecret),
    % URI encode values returned by oauth:sign/6 for the Authorization header
    Auth    = lists:flatten(string:join([ K++"=\""++oauth:uri_encode(V)++"\"" || {K,V} <- Signed], ", ")),
    OAuth   = "OAuth " ++ Auth,
    ContentType = "multipart/form-data;boundary=" ++ Boundary,                                
    Headers = [ {"Authorization", OAuth} ],
    Request = {URL, Headers, ContentType, Body},                                              
    httpc:request(post, Request, [], []).
相关问题