ASP.NET Web API:返回 401/未授权响应的正确方法

Posted

技术标签:

【中文标题】ASP.NET Web API:返回 401/未授权响应的正确方法【英文标题】:ASP.NET Web API : Correct way to return a 401/unauthorised response 【发布时间】:2015-09-21 05:22:43 【问题描述】:

我有一个 MVC webapi 站点,它使用 OAuth/token 身份验证来验证请求。所有相关控制器都具有正确的属性,并且身份验证工作正常。

问题在于,并非所有请求都可以在属性范围内获得授权 - 必须在控制器方法调用的代码中执行一些授权检查 - 返回 401 未授权响应的正确方法是什么?这种情况?

我已经尝试过throw new HttpException(401, "Unauthorized access");,但是当我这样做时,响应状态码是 500,我还得到了堆栈跟踪。即使在我们的日志记录 DelegatingHandler 中,我们也可以看到响应是 500,而不是 401。

【问题讨论】:

对于任何得到这个答案的人,我建议考虑适当的时间抛出HttpResponseException,而不是何时返回Unauthorized()。对“预期”错误使用异常有点反模式,因此如果在某些情况下您希望调用会犯此错误,则返回 Unauthorized() 可能是正确的调用。保存 HttpResponseException 以备不时之需。 请参阅github.com/aspnet/Mvc/issues/5507 进行一些讨论。 @Rikki,401 不是“预期”错误。 -- 这是一种特殊情况,应该会导致您中止您的工作流程(除了日志记录,您应该已经为任何异常执行此操作...) -- 无论如何,如果您想从控制器返回强类型结果(例如,为了便于单元测试),异常显然是最好的方法。 【参考方案1】:

作为其他答案的替代方案,如果您想在 ASP.NET 控制器中返回 IActionResult,也可以使用此代码。

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(Microsoft.AspNetCore.Http.StatusCodes.Status401Unauthorized, "My error message");
 return StatusCode(401, "My error message");

显然原因短语是可选的 (Can an HTTP response omit the Reason-Phrase?)

【讨论】:

这不再适用于 ASP.NET Core,ControllerBase 类(由 ASP.NET Core WebAPI 使用)不再具有接受 HTTP 状态代码的 Content 重载。 这是错误的。内容响应是 200 Ok 状态。服务器应该发送一个 401 并且客户端应该相应地处理。您不能将 200 作为 401 发送。这没有任何意义。如果客户收到 401,那不是 Oops,而是您的违法行为。 此代码发送 401 状态代码 (HttpStatusCode.Unauthorized),而不是 200。Content(...) 只是返回具有给定 HTTP 状态代码的任何给定内容的简写。如果你想发送 200 你可以使用Ok(...) @NickTurner - 这是 webapi2 Content() 方法命名不佳的一个论点,而不是因为这是错误的答案。由于 (status,message) 方法在 NetCore 中被重命名,我猜开发人员认为它的命名很糟糕。【参考方案2】:

您也遵循以下代码:

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 传递给构造函数,则无需再次设置 - 使用任何一个都可以【参考方案3】:

在.Net Core中可以使用

return new ForbidResult();

而不是

return Unauthorized();

它的优点是重定向到默认的未经授权的页面 (Account/AccessDenied),而不是直接给出 401

要更改默认位置,请修改您的 startup.cs

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

            )

【讨论】:

问题是关于 Web API。所以如果没有错,这将是一个无效的答案? API 不应返回“操作”,只返回结果。 403 是禁止的,而不是 401 未经授权的。关于区别here 有很好的解释【参考方案4】:

要添加到 ASP.NET Core >= 1.0 中的现有答案,您可以

return Unauthorized();

return Unauthorized(object value);

要将信息传递给客户端,您可以这样调用:

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

在客户端上,除了 401 响应之外,您还将获得传递的数据。例如,在大多数客户端上,您可以await response.json() 获取它。

【讨论】:

【参考方案5】:

您可以在 asp.net core 2.0 中使用以下代码:

public IActionResult index()

     return new ContentResult()  Content = "My error message", StatusCode = (int)HttpStatusCode.Unauthorized ;

【讨论】:

【参考方案6】:

只需返回以下内容:

return Unauthorized();

【讨论】:

我认为接受者专门回答了 OP 的问题。我的回答回答了问题的标题“ASP.NET Web API:返回 401/未授权响应的正确方法” 有人知道为什么没有重载版本的消息吗? @Simon_Weaver 不知道为什么,但您可以使用 return Content<string>(HttpStatusCode.Unauthorized, "Message"); 来执行此操作。 这应该是正确的答案。 1是正确的。 2)如果这在以后的框架中发生变化,您不必更改代码。 3)您不需要向 401 提供原因。这应该由客户端而不是服务器来处理。 这是在哪个库中?【参考方案7】:

您应该从您的 API 方法中抛出 HttpResponseException,而不是 HttpException

throw new HttpResponseException(HttpStatusCode.Unauthorized);

或者,如果您想提供自定义消息:

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

【讨论】:

HttpResponseException 是 NuGet 包 Microsoft.AspNetCore.Mvc.WebApiCompatShim 的一部分,它提供了 ASP.NET Core MVC 与 ASP.NET Web API 2 的兼容性。也就是说,它允许您以非核心方式进入核心项目。所以对于核心项目,这不是“正确的方式”。 Wasnt' HttpResposeException 从 .netcore 中删除? ***.com/questions/47142142/…【参考方案8】:

您收到 500 响应代码,因为您抛出了异常(HttpException),表明某种服务器错误,这是错误的方法。

只需设置响应状态码.e.g

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

【讨论】:

这有点奇怪,异常将 HTTP 状态代码作为参数,而智能感知文档说这是发送给客户端的状态代码 - 我希望避免自己直接改变响应因为这似乎很容易出错,将其视为全局状态 基本 Web API 控制器不公开 Response 属性。

以上是关于ASP.NET Web API:返回 401/未授权响应的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

当用户未经身份验证时,ASP.NET Core 5 Web API 返回 404 代码而不是 401

ASP.Net Core 3 API 总是返回 401- JwtBearer

如何使 ASP.NET Web API 正确响应 403 或 401?

ASP.NET Core API 在从 React 客户端调用时返回 401

每当我发送包含 Bearer 令牌的请求时,ASP.Net Core API 总是返回 401 未授权

ASP.NET Web API 身份验证