Basic認証の方法とハマったこと

前に書いたWCFサービスをAndroidから利用する際に、ズルズルで見せるわけに行かないのでサーバー側でBasic認証を行うように設定しました。
開発はバージョン2.1のAVDを使用して行なっていたのですが、どうも認証をうまく通ってくれず400 Bad Requestが返って来ます。アプリを作る部分も多かったので最初はスルーして進めていたのですが、バージョン2.3.3の実機でテストした際は何の問題も無く動作するんです。おや??と思いパケットを調べてみました。
まずは正常なバージョン2.3.3からのBasic認証の流れ。

  1. Request(Authorizationヘッダー無し)
  2. Response(401 Unauthorized)
  3. Request(Authorizationヘッダー有り)
  4. Response(200 Ok)

となっていました。初めて知ったのですが2回やり取りを行なっています。一度目は通常通りリクエストを行い401が返ってきたら今度は認証情報を載っけてリクエストを行います。これはブラウザでBasic認証のサイトを開いた際の動作と同じで、ブラウザは401が返ってくるとユーザー名、パスワードを入力するダイアログを表示し、ユーザーの入力後その情報を載せてリクエストして認証を行います。
続いてAVDの2.1の流れです。

  1. Request(Authorizationヘッダー無し)
  2. Response(401 Unauthorized)
  3. Request(Authorizationヘッダー有り)
  4. Response(400 Bad request)

先ほどと流れが同じなのになぜか400が返って来ています。最初はさっぱりわかりませんでしたがパケットをよく見てみると、2回あるリクエストの両方に送信するデータに当たるPayload部分がなぜかありませんでした。当然サーバー側はJSON形式のデータを期待している訳ですから認証を通ったとしても不正なリクエストとして扱われてしまうのも納得します。
とりあえずバージョン違いでなにか問題があるのかと思いググってみるとありました。
Android2.1、Basic認証でハマる - Takazudo hamalog
どうやら2.1では調子がわるいようです。でも国内で出回っているAndroidをフォローしようとすると最低2.1ぐらいまではやっておかないとなぁ、という気持ちがありました。
何か別の方法はと考え、

	Credentials credentials = new UsernamePasswordCredentials("UserName","Password");
	AuthScope scope = new AuthScope("Site", Port番号);
	httpClient.getCredentialsProvider().setCredentials(scope, credentials);

とやって認証情報を設定していたのですが、直接ヘッダーに認証情報を設定してしまうように変えてみました。

	request.setHeader("Authorization", AuthorizationString);

AuthorizationStringには「ユーザー名:パスワード」をBASE64エンコードした文字列をセットします。こうすると2.1、2.2、2.3.3のどのバージョンでも問題無く動作しています。しかも初回から認証情報を載せて要求を行うため、やり取りが1回に減っています。この方法が正しいのかどうかはいまいち確信が持てませんが、とりあえずこの方法でBasic認証を行いたいと思います。