C# で OAuth

観測気球

収集物の記録書庫 a data archive of collection -- collectible toys

[要旨] C# で OAuth 対応アプリケーションを書くときに、Google Code で公開されている OAuthBase.cs を参考にする人が多いと思うんですが、この OAuthBase.cs をそのまま使うと、引数にマルチバイト文字(日本語とか中国語とか)を含むhttpリクエストの認証が失敗します。その解決方法について、書いてみました。
[キーワード] C#,OAuth,Twitter,認証

« 04月05日のココロ日記(BlogPet) | トップページ | 04月13日のココロ日記(BlogPet) »

2009.04.07

C# で OAuth

C# で OAuth 認証対応アプリケーションを書くときは、"oauth - Google Code" の OAuthBase.cs を使うと、かなり楽に書けます。この OAuthBase.cs には、OAuth を実装する上でいちばんややこしい「signature を生成する処理」が入っています。

この OAuthBase.cs を利用しているものとしては、

などがあります。

私は、Twitter oAuth with .NET | Shannon Whitley を参考にしつつ、tumblen3 に、Twitter の API を OAuth 越しに使う処理を 組み込んでみました。(Webアプリケーションではなく、)デスクトップアプリケーションで OAuth 認証を使う例になっています。Webアプリケーションの実装例は巷に多数ありますが、デスクトップクライアントの実装例はまだほとんどないので、クライアントを作ろうとしている人には参考になるのではないかと思います。なお、デスクトップアプリケーション(デスクトップクライアント)で OAuth 認証を使うためのあれこれは、後日、別途、記事を書く予定です。

で、今回、signature を生成するのに OAuthBase.cs を利用しているのですが、「リクエストトークンの取得」から「アクセストークンの取得」までは問題なく動きました。API の OAuth 越しでの実行も、Twitter の timeline の取得、favorite の登録、ダイレクトメッセージの受信、と、ここまでは順調に動きました。このまま何の問題もなく他の API も動くのかと思いきや、「つぶやきの投稿」で 401 Unauthorized (認証失敗) のエラーが発生。投稿内容をいろいろ変えて試してみた結果、英数字だけのつぶやきは問題なく投稿できるものの、漢字が混じると「認証失敗」になることがわかりました。なんで認証失敗になるのかというと、こちらで生成した signature と Twitter側で生成した signature が一致しないのが原因であることが判明。詳しく調べてみたところ、OAuthBase.cs 内の URLエンコード(パーセントエンコード)処理 OAuthBase.UrlEncode(string value) がマルチバイト文字のことをまったく考慮せずにコーディングされていることを突き止めました。

        /// <summary>
        /// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case.
        /// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth
        /// </summary>
        /// <param name="value">The value to Url encode</param>
        /// <returns>Returns a Url encoded string</returns>
        protected string UrlEncode(string value)
        {
            StringBuilder result = new StringBuilder();

            foreach (char symbol in value)
            {
                if (unreservedChars.IndexOf(symbol) != -1)
                {
                    result.Append(symbol);
                }
                else
                {
                    result.Append('%' + String.Format("{0:X2}", (int)symbol));
                }
            }

            return result.ToString();
        }

結局、以下のような、 OAuthBase.UrlEncode(string value, Encoding encode) というメソッドを書いて対応しました。

        protected string UrlEncode(string value, Encoding encode)
        {
            StringBuilder result = new StringBuilder();
            byte[] data = encode.GetBytes(value);
            int len = data.Length;

            for (int i = 0; i < len; i++)
            {
                int c = data[i];
                if (c < 0x80 && unreservedChars.IndexOf((char)c) != -1)
                {
                    result.Append((char)c);
                }
                else
                {
                    result.Append('%' + String.Format("{0:X2}", (int)data[i]));
                }
            }

            return result.ToString();
        }

ということで、もし、OAuthBase.cs を使っていて、「認証失敗」のまま先に進めていない人がいるようでしたら、上記のコードを使ってみてください。

関連記事

投稿者: tsupo 2009.04.07 午前 03:01 | 固定リンク | このエントリーをはてなブックマークに追加 | このエントリを del.icio.us に登録 このエントリの del.icio.us での登録状況 | このエントリを Buzzurl に追加このエントリの Buzzurl での登録状況 | このエントリをlivedoorクリップに登録 このエントリのlivedoorクリップでの登録状況 このエントリをlivedoorクリップに登録している人の数 | 酢鶏巡回中

楽天市場


Twitter」カテゴリ内の最近の記事

プログラミング」カテゴリ内の最近の記事

品揃え豊富で安い!NTT-X Store


アマゾンわくわく探検隊

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/6737/44592074

この記事へのトラックバック一覧です: C# で OAuth:

コメント


Jaikuにはポストできるんですが、Twitterには「abc!@#」などのアルファベットだけではポストできるのにマルチバイトになると401エラー(シグネチャが合わない?)になってしまい悩んでます。

たとえば、「あ」status=%E3%81%82(シグネチャ算出時:status%3D%25E3%2581%2582)
とするとダメです。
「abc!@#」status=abc%21%40%23(シグネチャ算出時:status%3Dabc%2521%2540%2523)
だとOKなんですが><

投稿者: kichi (2009.04.12 午前 04:18)


2009年4月12日のいつごろからかわかりませんが、Twitter のサーバ側の OAuth の(クライアント側のsignatureと照合するための)signature生成処理がおかしいようです。シングルバイト文字のみの場合は問題なく投稿できますが、マルチバイト文字が含まれる場合は 401 エラーになるようです。

すでに、問題は Twitter に報告されているようで、現在、Twitter 側の対応(修正)待ちです。

投稿者: tsupo (2009.04.14 午前 12:12)


書き換えたコードでも、「UrlEncodeは1個の引数を指定できません」みたいなエラーが出るので、
protected string UrlEncode(string value, Encoding encode)
{
StringBuilder result = new StringBuilder();
byte[] data = encode.GetBytes(value);
int len = data.Length;
    //省略
}

protected string UrlEncode(string value)//変更部分
{
StringBuilder result = new StringBuilder();
byte[] data = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(value); //変更部分
int len = data.Length;
      //省略
}
という風に書き換えたら日本語でもエラーが出ることなく認証できました。
文字コード指定を"shift-jis"にしても、うまく表示できませんでした。(ブラウザのエンコードの問題かも?)

投稿者: うきょう (2011.01.20 午前 01:05)


Encoding まわりは、.NET Framework の版数(や C# のバージョン)によって、微妙に挙動が違うかもしれません。
Twitter に関しては、文字コードは UTF-8 じゃないと駄目だと思います。

投稿者: tsupo (2011.01.20 午後 10:12)

コメントを書く




※イタズラ防止のため、メールアドレスを入力しないと投稿できません。

次からのコメント入力の手間を省くために、名前やメールアドレスをcookieに記憶しますか?


URL を入力すると、その URL にリンクがはられます。
なお、メールアドレスは公開されません。ご安心ください。


ワード

ニッセン

fujisan.co.jp

楽天市場