【问题标题】:ASP.NET Web API : Correct way to return a 401/unauthorised responseASP.NET Web API:返回 401/未授权响应的正确方法
【发布时间】: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 不是“预期”错误。 -- 这是一种特殊情况,应该会导致您中止您的工作流程(除了日志记录,您应该已经为任何异常执行此操作...) -- 无论如何,如果您想从控制器返回强类型结果(例如,为了便于单元测试),异常显然是最好的方法。

标签: c# asp.net-mvc authorization


【解决方案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 中删除? stackoverflow.com/questions/47142142/…
      【解决方案8】:

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

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

      Response.StatusCode = (int)HttpStatusCode.Unauthorized;
      

      【讨论】:

      • 这有点奇怪,异常将 HTTP 状态代码作为参数,而智能感知文档说这是发送给客户端的状态代码 - 我希望避免自己直接改变响应因为这似乎很容易出错,将其视为全局状态
      • 基本 Web API 控制器不公开 Response 属性。
      猜你喜欢
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 1970-01-01
      相关资源
      最近更新 更多