Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET Web API:返回401/未经授权响应的正确方法_C#_Asp.net Mvc_Authorization - Fatal编程技术网

C# ASP.NET Web API:返回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

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

问题在于,并非所有请求都能在属性范围内得到授权-一些授权检查必须在控制器方法调用的代码中执行-在这种情况下,返回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
),而不是200
Content(…)
只是用给定的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);