ASP.NET Web API:401 /不正な応答を返す正しい方法


98

OAuth /トークン認証を使用してリクエストを認証するMVC webapiサイトがあります。関連するすべてのコントローラーに適切な属性があり、認証は正常に機能しています。

問題は、すべてのリクエストを属性のスコープで承認できないことです。一部の承認チェックは、コントローラメソッドによって呼び出されるコードで実行する必要があります。この場合、401の不正な応答を返す正しい方法は何ですか。

私は試しましたがthrow new HttpException(401, "Unauthorized access");、これを行うと、応答ステータスコードが500になり、スタックトレースも取得されます。ログ記録のDelegatingHandlerでも、応答が401ではなく500であることがわかります。


1
この答えをすぐにHttpResponseException理解する人には、を返すタイミングとを返すタイミングの適切な時間について考えることをお勧めしUnauthorized()ます。「予期された」エラーに例外を使用することは少しアンチパターンであるため、呼び出しがこの間違いをすることが予想される場合、戻るのUnauthorized()はおそらく正しい呼び出しです。HttpResponseException本当に予想外のために保存します。
Rikki

議論についてはgithub.com/aspnet/Mvc/issues/5507を参照してください。
リッキ

@ Rikki、401は「予期された」エラーではありません。-これは例外的な状況であり、ワークフローを中止する必要があります(おそらく、例外のためにすでに実行しているロギングを除いて...)-とにかく、コントローラーから強い型付けの結果を返したい場合(たとえば、ユニットテストを簡単にするために、例外は明らかに最適なルートです。
BrainSlugs83 2018年

回答:


144

あなたは投げるべきであるHttpResponseExceptionあなたのAPIの方法、ありませんからHttpException

throw new HttpResponseException(HttpStatusCode.Unauthorized);

または、カスタムメッセージを提供する場合:

var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "Oops!!!" };
throw new HttpResponseException(msg);

95

以下を返すだけです:

return Unauthorized();

2
受け入れられた人はOPの質問に明確に答えると思います。私の答えは、質問のタイトル「ASP.NET Web API:401 /不正な応答を返す正しい方法」に答えます
JohnWrensby

3
メッセージ付きのこのオーバーロードバージョンがない理由を誰かが知っていますか?
Simon_Weaver

5
@Simon_Weaver理由はわかりませんが、return Content<string>(HttpStatusCode.Unauthorized, "Message");これを行うにはa を使用できます。
リッキ

2
これが正解です。1それは正しいです。2)これが後のフレームワークで変更された場合、コードを変更する必要はありません。3)401に理由を提供する必要はありません。これはサーバーではなくクライアントで処理する必要があります。
Nick Turner、

1
これはどのライブラリにありますか?
Nae、

19

他の回答の代わりに、IActionResultASP.NETコントローラー内でを返す場合は、このコードを使用することもできます。

ASP.NET

 return Content(HttpStatusCode.Unauthorized, "My error message");

更新:ASP.NET Core

上記のコードはASP.NET Coreでは機能しません。代わりに次のいずれかを使用できます。

 return StatusCode((int)System.Net.HttpStatusCode.Unauthorized, "My error message");
 return StatusCode(401, "My error message");

どうやら理由フレーズはかなりオプションです(HTTP応答は理由フレーズを省略できますか?


1
これはASP.NET Coreでは機能しなくなり、ControllerBaseクラス(ASP.NET Core WebAPIで使用)ContentはHTTPステータスコードを受け入れるオーバーロードを持たなくなりました。

これは間違っています。コンテンツレスポンスは200 Okステータスです。サーバーは401を送信し、クライアントはそれに応じて処理する必要があります。200を401として送信することはできません。意味がありません。クライアントが401を取得した場合、それはエラーです。法律違反です。
Nick Turner、

このコードはHttpStatusCode.Unauthorized、200ではなく401ステータスコード()を送信していContent(...)ます。特定のHTTPステータスコードで特定のコンテンツを返すための省略形にすぎません。200を送信する場合は、次の方法を使用できますOk(...)
Alex AIT

@NickTurner-これはwebapi2 Content()メソッドの名前が不適切であるため、これは間違った答えではないためです。(status、message)メソッドはNetCoreで名前が変更されているので、開発者は名前が不適切であることに同意していると思います。
クリスFキャロル

9

HttpException何らかのサーバーエラーを示す例外()をスローしているため、500応答コードが返されますが、これは間違ったアプローチです。

応答ステータスコードを設定するだけです。

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

例外がHTTPステータスコードをパラメーターとして受け取り、インテリセンスのドキュメントがこれがクライアントに送信されるステータスコードであると言うのは少し奇妙ですそのグローバルな状態
GoatInTheMachine 2015

1
基本Web APIコントローラーはResponseプロパティを公開しません。
LukeH 2015

3

ASP.NET Core> = 1.0の既存の回答に追加するには、次のことができます

return Unauthorized();

return Unauthorized(object value);

クライアントに情報を渡すには、次のような呼び出しを行います。

return Unauthorized(new { Ok = false, Code = Constants.INVALID_CREDENTIALS, ...});

クライアントでは、401応答のほかに、データも渡されます。たとえば、ほとんどのクライアントではawait response.json()、それを取得できます。


3

.Net Coreで使用できます

return new ForbidResult();

の代わりに

return Unauthorized();

これは、ストレート401を与えるよりも、デフォルトの無許可ページ(Account / AccessDenied)にリダイレクトするという利点があります。

デフォルトの場所を変更するには、startup.csを変更します

services.AddAuthentication(options =>...)
            .AddOpenIdConnect(options =>...)
            .AddCookie(options =>
            {
                options.AccessDeniedPath = "/path/unauthorized";

            })

問題は、Web APIについてです。だから、もし間違っていなければ、これは無効な答えでしょうか?APIは「アクション」を返すのではなく、結果のみを返します。
Niels Lucas

1

あなたはasp.netコア2.0でフォローコードを使用することができます:

public IActionResult index()
{
     return new ContentResult() { Content = "My error message", StatusCode = (int)HttpStatusCode.Unauthorized };
}

1

また、次のコードに従います。

var response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
      Content = new StringContent("Users doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
      StatusCode = HttpStatusCode.NotFound
 }
 throw new HttpResponseException(response);

コンストラクタに渡す場合は、StatusCodeを再度設定する必要はありません。どちらを使用してもかまいません
Jon Story
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.