我正在尝试扩展此库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, [], []).
答案 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
)。Content-Type
和Content-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, [], []).