C# ASP.NET Web API:返回401/未经授权响应的正确方法
我有一个MVC webapi站点,它使用OAuth/令牌身份验证来验证请求。所有相关控制器都具有正确的属性,并且身份验证工作正常 问题在于,并非所有请求都能在属性范围内得到授权-一些授权检查必须在控制器方法调用的代码中执行-在这种情况下,返回401未经授权响应的正确方法是什么C# ASP.NET Web API:返回401/未经授权响应的正确方法,c#,asp.net-mvc,authorization,C#,Asp.net Mvc,Authorization,我有一个MVC webapi站点,它使用OAuth/令牌身份验证来验证请求。所有相关控制器都具有正确的属性,并且身份验证工作正常 问题在于,并非所有请求都能在属性范围内得到授权-一些授权检查必须在控制器方法调用的代码中执行-在这种情况下,返回401未经授权响应的正确方法是什么 我尝试过抛出新的HttpException(401,“未授权访问”),但当我这样做时,响应状态代码是500,我还得到了堆栈跟踪。即使在我们的日志DelegatingHandler中,我们也可以看到响应是500,而不是401
我尝试过抛出新的HttpException(401,“未授权访问”)代码>,但当我这样做时,响应状态代码是500,我还得到了堆栈跟踪。即使在我们的日志DelegatingHandler中,我们也可以看到响应是500,而不是401 您将得到500个响应代码,因为您正在抛出一个异常(
HttpException
),该异常指示某种服务器错误,这是错误的方法
只需设置响应状态代码
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
您应该从API方法中抛出一个,而不是:
或者,如果要提供自定义消息:
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");
显然,原因短语是非常可选的()您可以在asp.net core 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响应之外,您还将拥有传递的数据。例如,在大多数客户端上,您可以
等待response.json()
来获取它。在.Net核心中,您可以使用
return new ForbidResult();
而不是
return Unauthorized();
这样做的好处是重定向到默认的未经授权页面(帐户/访问被拒绝),而不是直接给出一个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);
这有点奇怪,异常将HTTP状态代码作为参数,intellisense文档说这是发送给客户端的状态代码-我希望避免自己直接改变响应,因为这似乎容易出错,鉴于其全局状态,基本Web API控制器不公开
响应
属性。我认为已接受的属性专门回答了OP的问题。我的答案回答了题为“ASP.NET Web API:返回401/未经授权响应的正确方法”的问题。有人知道为什么没有带消息的重载版本吗?@Simon_Weaver不知道为什么,但你可以使用返回内容(HttpStatusCode.Unauthorized,“message”)代码>以执行此操作。这应该是正确答案。这是正确的。2) 如果这在以后的框架中发生更改,则不必更改代码。3) 你不需要为401计划提供理由。这应该由客户端而不是服务器来处理。这在哪个库中?这在ASP.NET Core中不再起作用,ControllerBase
类(由ASP.NET Core WebAPI使用)不再具有接受HTTP状态代码的Content
重载。这是错误的。内容响应是200 Ok状态。服务器应该发送401,客户端应该相应地处理。您不能将200作为401发送。这没有道理。如果客户端收到401,则不是Oops,而是您违反了法律。此代码发送的是401状态代码(HttpStatusCode.Unauthorized
),而不是200Content(…)
只是用给定的HTTP状态码返回任何给定内容的简写。如果你想发送200,你可以使用Ok(…)
@NickTurner——这是webapi2 Content()方法命名不当的一个原因,不是因为这是错误的答案。由于(status,message)方法在NetCore中被重命名,我猜开发人员都同意它的名称不好。对于任何一个在这一行中找到答案的人,我建议考虑在适当的时间抛出一个HttpResponseException
而不是何时返回一个Unauthorized()
。将异常用于“预期”错误有点反模式,因此,如果在某些情况下您预期调用会犯此错误,则返回Unauthorized()
可能是正确的调用。保存HttpResponseException
以了解真正意外的情况。有关讨论,请参阅。@Rikki,401不是“预期”错误。--这是一种异常情况,会导致您中止工作流程(可能除了日志记录,您应该已经针对任何异常进行了日志记录…)——无论如何,如果您希望从控制器返回强类型结果(例如,为了便于单元测试),异常显然是最好的途径。如果将状态码传递给构造函数,则无需再次设置状态码-使用任何一种都是正确的。问题是关于web API的。如果我没有错的话,这将是一个无效的答案?API不应返回“操作”,只有results.403被禁止,而不是401未经授权。关于差异有一个很好的解释HttpResponseException
是NuGet软件包Microsoft.AspNetCore.Mvc.WebApiCompatShim
的一部分,该软件包提供了ASP.NET Core Mvc与ASP.NET Web API 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);