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

ASP.NET Web API : Correct way to return a 401/unauthorised response

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

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

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

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

只需设置响应状态码即可。例如

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

你应该抛出一个 HttpResponseException from your API method, not HttpException:

throw new HttpResponseException(HttpStatusCode.Unauthorized);

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

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

只需 return 以下内容:

return Unauthorized();

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

ASP.NET

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

更新:ASP.NET核心

以上代码在 ASP.NET 核心中不起作用,您可以使用其中之一:

 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");

显然,短语的原因是可选的 ()

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

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

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

return Unauthorized();

return Unauthorized(object value);

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

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

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

在.Net Core中可以使用

return new ForbidResult();

而不是

return Unauthorized();

这有利于重定向到默认的未授权页面 (Account/AccessDenied) 而不是直接给出 401

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

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

            })

您还关注了这个代码:

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);