搜尋此網誌

2022年9月16日 星期五

C# 產生 Twitter API OAuth1.0 的 signature

緣起:


    好的,本來這東西我昨天應該就該弄好的,但因為發生了點事,導致我那天心情都很低落,整天都在 LINE 的親友群上跟家人們諮詢 (當了一天的薪水小偷),不過別擔心,我撐過去了,Anyway,今天又有進展了,續這篇文章,雖然能用 PostMan 送 tweet 了,但我需要用 C# 寫程式來做這件事,Request Header 有一個很重要的值,叫 oauth_signature,他必需經過計算才能得到。

    官方文章有很詳盡的教學,我都是照著這篇文章做的。


C# SHA1:


    首先,我們要使用的簽章方法是 SHA1,大學在資安課有上過,雖然詳細的步驟根本就忘了,但只要知道它是一個 hash function 就好,這種這麼常用的東西,C# 肯定會提供的對吧 ? 果不其然,隨便 Google 一下就找到了。

    由於簽章時除了輸入的字串,還需提供一個 security key 來運作,所以我們需要一個能用 security key 來做 hash 的 SHA1 function,我在這邊找到解答。滿簡單的,使用時要引入 System.Security.Cryptography,然後把 function 直接 copy paste 到自己的程式裡就好。


    傳入的 message 原始字串,secret 是 security key (還是叫 signing key 來著?),它最後會回傳 base64 格式的字串。為了測試這個 function 是不是我需要的,我在這邊就拿官方提供的範例字串來做,

這個傳進 message

這個傳進 secure

    最後 function 回傳的字串是 hCtSmYh+iHYCEqBWrE7C7hYmtUk=,跟範列提供的一模一樣,所以可以確定這個 function 就是我們要的。


解析 POST 資料:


    我用 POST Man 隨便送了一個推,然後開啟 Console,可以看到我們的 Request 的完整資訊。


    重點是 Request Header 那邊,除了 oauth_timestamp、oauth_nonce、oauth_signature、其它的參數都能從我們的 Twitter APP 得到,然後那個 oauth_signature_method 跟 oauth_version 都是固定的。

    我們的目標就是組織這些資料,讓他們最後 hash 出來的值等於那筆 POST 的 oauth_signature 值,也就是 axlnt%2B9rEcrh%2FguH32bG7UrQUSA%3D。

    先把我們的 key、secure、token 那些都存到變數中


    我們要用這些變數組成一個 parameter_string,他的組成規則是這樣,每個參數都要用 "key=value" 的格式,然後用 & 串接,而且也有先後順序 -> 依 key 的字母順序,所以排下來會是

  1. oauth_consumer_key
  2. oauth_nonce
  3. oauth_signature_method
  4. oauth_timestamp
  5. oauth_token
  6. oauth_version

    要注意的是,每個 key 跟value 都要先編碼成 base64 格式,在這邊我們可以引入 System.Net,使用 WebUtility.UrlEncode 來做。最後程式碼會是這樣。


    這時的 parameter_string 會長這樣

oauth_consumer_key=v2MRsZZH77VpzReb6lNlKXFrW&oauth_nonce=0TkFqck29GL&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1663290663&oauth_token=1057816229774221312-U1Ao7ZdOzLGUhMdT5nZfASXjejTYmc&oauth_version=1.0


    再來要產生 base_string ,它會是 "你的請求方法(大寫)"+"&"+你請求的目標網址(base64編碼)+"&"+parameter_string(base64編碼),寫成程式的話會是這樣。


    到這裡,我們的 message string 就完成了,再來是signing key 的部份,這個簡單,就把 consumer secret 跟 OAuth token secret 用 base64 編碼,然後再用 "&" 號連接在一起就好


    最後再把 base_string 跟 signing_key 丟給 SignData function,就能得到正確的簽章了。


碰上的問題:


    那時碰上的最大問題是,範例的 end point 是 https://api.twitter.com/1.1/statuses/update.json,傳過去的 Content-Type 是 application/x-www-form-urlencoded,它在生成 parameter_string 時,也有把 Request 的 Body 部份加進去。


一樣編成 base64,然後用 "&" 符號接在 parameter_string 後面

    啊我在 POST Man 上操作時,end point 是 https://api.twitter.com/2/tweets,Content-Type 是 application/json,Body 的內容是 json 格式


    我原本以為我的 Body 也要加在 parameter_string 後


    但這樣做算出來的 hash 值怎麼樣都不會跟 POST Man 算出來的一樣,不加入那個 body_string 後才得到正確的值,我也不是很清楚為啥,反正它不用加 body 的內容就是了。

    現在能成功算出 hash 值,再來就是寫 POST 的功能了。

    PS:我後來發現,經過 SignData function hash 出來的值還要再給它用 base64 編碼過才會是正確的簽章值 (我那時只比對前面的部份,看太快沒注意到)。

沒有留言:

張貼留言