ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个 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 不是“预期”错误。 -- 这是一个异常情况,应该会导致您中止您的工作流程(除了日志记录,您应该已经为任何异常执行此操作......) -- 无论如何,如果您想从控制器返回强类型结果(例如为了便于单元测试),异常显然是最好的途径。

L
LukeH

您应该从 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 的兼容性。也就是说,它允许您在 Core 项目中采用非核心方式。所以对于核心项目,这不是“正确的方式”。
没有从 .netcore 中删除 HttpResposeException 吗? stackoverflow.com/questions/47142142/…
J
JohnWrensby

只需返回以下内容:

return Unauthorized();

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

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

ASP.NET

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

更新:ASP.NET 核心

上面的代码在 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 中被重命名,我猜开发人员同意它的命名很糟糕。
D
DGibbs

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

只需设置响应状态码.eg

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

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

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

return Unauthorized();

return Unauthorized(object value);

要将信息传递给客户端,您可以进行如下调用:

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

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


m
mattbloke

在 .Net Core 你可以使用

return new ForbidResult();

代替

return Unauthorized();

它的优点是重定向到默认的未经授权的页面(帐户/访问拒绝),而不是直接给出 401

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

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

            })

问题是关于 Web API。所以如果没有错,这将是一个无效的答案? API 不应返回“操作”,而应仅返回结果。
403 是禁止的,而不是 401 未经授权的。关于差异有一个很好的解释here
完全错误。正如@Mars 所说,403 是禁止的,而 401 是用于未经授权的请求
A
AminRostami

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

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

K
Kamrul Hasan

您还遵循以下代码:

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 传递给构造函数,则无需再次设置它 - 使用其中任何一个都可以