web-dev-qa-db-ja.com

なぜ私のRESTサービス.NETクライアントは認証ヘッダーなしですべてのリクエストを送信し、認証ヘッダーで再試行するのですか?

たまたま、クライアントが基本認証を使用することを要求するAPIを使用してREST Webサービスを実行します。サービスとのインターフェース方法を示す、さまざまな言語のきちんとしたサンプルのセットを作成しました。 。現在、サービスのIISログを確認しており、次のパターンが頻繁に発生することを確認しています。

  • リクエストが来て、HTTPコード401で拒否されます
  • 同じリクエストが再送されて成功します

これは、最初のリクエストがAuthorizationヘッダーなしで送信され、2番目のリクエストが正しいヘッダー付きで送信されて成功したように見えます。ほとんどの場合、ログレコードには、.NETサンプルに植え付けたのと同じ文字列である「user-agent」が含まれています。

したがって、問題は.NETプログラムのみにあると思います。サンプルコードでは問題が再現されていないため、ユーザーが何らかの方法でコードを変更したか、独自に作成したと思います。

ユーザーに連絡してみましたが、どうやら彼らは研究に時間を費やしたくないようです。したがって、.NETプログラムのこの動作につながる可能性が最も高いシナリオを見つけるのは良いことです。

なぜ彼らはこれをするのでしょうか?なぜ彼らは最初の試みでヘッダーを付けないのでしょうか?

17
sharptooth

これは、次の方法で公開されるHttpClientクラスとHttpWebRequestクラスのデフォルトの動作です。

注:以下のテキストは、質問で説明されている問題を引き起こす次善の動作を説明しています。ほとんどの場合、このようなコードを書くべきではありません。代わりに、修正されたコードまで下にスクロールしてください

どちらの場合も、NetworkCredenatialオブジェクトをインスタンス化し、そこにユーザー名とパスワードを設定します

var credentials = new NetworkCredential( username, password );

HttpWebRequest --set .Credentialsプロパティを使用する場合:

webRequest.Credentials = credentials;

HttpClientを使用する場合-資格情報オブジェクトをHttpClientHandlerに渡します( ここ から変更されたコード):

var client = new HttpClient(new HttpClientHandler() { Credentials = credentials })

次に、Fiddlerを実行して、リクエストを開始します。次のように表示されます。

  • リクエストはAuthorizationヘッダーなしで送信されます
  • サービスはHTTP401およびWWW-Authenticateで応答します:Basic realm = "UrRealmHere"
  • リクエストは適切なAuthorizationヘッダーで再送信されます(そして成功します)

この動作は説明されています ここ -クライアントはサービスがBasicを必要とすることを事前に知らず、認証プロトコルをネゴシエートしようとします(そしてサービスがDigest送信が必要ですOpenのBasicヘッダーは役に立たず、クライアントを危険にさらす可能性があります)。

注:ここで、次善の動作の説明が終了し、より良いアプローチが説明されます。ほとんどの場合、上からのコードではなく、下からのコードを使用する必要があります。

サービスにBasicが必要であることがわかっている場合は、次の方法で余分なリクエストを削除できます。

.Credentialsを設定せず、代わりに here のコードを使用してヘッダーを手動で追加します。ユーザー名とパスワードをエンコードします。

var encoded = Convert.ToBase64String( Encoding.ASCII.GetBytes(
    String.Format( "{0}:{1}", username, password ) ) );

HttpWebRequestを使用する場合は、ヘッダーに追加します。

request.Headers.Add( "Authorization", "Basic " + encoded );

HttpClientを使用する場合は、デフォルトのヘッダーに追加します。

client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue( "Basic", encoded );

これを行うと、リクエストは毎回適切な認証ヘッダーとともに送信されます。 .Credentialsを設定しないでください、そうでない場合はユーザー名またはパスワードが間違っていることに注意してください同じリクエストが、間違った資格情報を使用して2回送信され、もちろん両方の時間でHTTP401が生成されます。

40
sharptooth