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

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

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

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

201013 次浏览

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

只需设定回应状态码

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

您应该从 API 方法抛出一个 HttpResponseException,而不是 HttpException:

throw new HttpResponseException(HttpStatusCode.Unauthorized);

或者,如果希望提供自定义消息:

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

只需返回以下内容:

return Unauthorized();

如果您想在 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");

显然,原因短语是非常可选的(HTTP 响应可以省略原因短语吗?)

你可以在 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()得到它。

你可以使用

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

确保“ Startup.cs”中的行顺序是这样的,而不是相反:

app.UseAuthentication(); // the order is important
app.UseAuthorization();

这就是我的问题所在。