纠正需要授权的资源的http状态码

如果用户尝试访问需要用户login的页面,似乎有很多关于正确http状态码的混淆。

那么基本上显示login页面时会发送什么状态码?

我很确定我们需要在4xx范围内使用状态码。

我不是在谈论HTTP身份validation,所以至less有一个状态码是我们不打算使用的( 401 Unauthorized )。

现在我们应该使用什么? 答案(也在这里)似乎有所不同:

根据这里的答案,我们应该使用403 Forbidden

但是在状态码的描述中是:

授权不起作用,请求不应重复。

那么这看起来不是正确的。 由于授权会帮助。

所以让我们来看看其他的答案。 这里的答案甚至不使用4xx范围,而是使用302 Found

302 Found状态码的描述:

请求的资源暂时驻留在不同的URI下。 由于redirect有时可能会被改变,所以客户端应该继续使用Request-URI来处理将来的请求。 如果由Cache-Control或Expires标头字段指示,则该响应仅可caching。

我想这也不是我想要的。 由于它不是位于不同URI下的请求资源。 而是一个完全不同的资源(login页面与authentication内容页面)。

所以我走了,另一个解决scheme令人惊讶的另一个答案 。

这个答案build议我们select400 Bad Request

这个状态码的描述是:

由于格式错误,服务器无法理解请求。 客户端不应该不加修改地重复请求。

我认为服务器很好的理解了这个请求,但是只是在用户被authentication之前拒绝访问。

另一个答案也说, 403回应是正确的,但它结束于:

如果这是一个面向公众的网站,而您正尝试拒绝基于会话cookie的访问[这就是我所做的],200有一个合适的主体来指示需要login或302临时redirect到login页面最好。

所以403是正确的,但200302是最好的。

嘿! 这就是我正在寻找的:最好的解决scheme。 但最好不要和正确的一样吗? 为什么这是最好的?

感谢所有那些已经到这个问题的人:)

我知道我不应该太担心。 而且我认为这个问题更具假设性(不是真的,而是因为没有更好的词而使用它)。

但这个问题现在已经困扰了我一段时间了。

如果我本来是一个经理人(他们总是拿起一些很酷的听起来的话),我会说:但是,但是,但是,安宁是重要的。 🙂

那么:在上述情况下使用状态码the right way™是什么(如果有的话)?

TL;博士

当用户尝试访问需要login的页面时,什么是正确的http状态码响应?

如果用户没有提供任何凭证,并且您的API需要他们,请返回401 - Unauthorized 。 这将挑战客户这样做。 关于这个特定的情况通常很less有争议。

如果用户提供了有效的凭证,但是他们不足以访问所请求的资源(也许凭证是用于免费账户的,但所请求的资源仅用于付费用户),您可以select一些选项HTTP代码定义:

  1. 返回403 - Forbidden 。 这是更具描述性的,通常被理解为: “提供的凭据是有效的,但仍然不足以授予访问权限”
  2. 返回401 - Unauthorized 。 如果您对安全性有偏见,您可能不想像上面(1)中返回的那样向客户提供额外的信息
  3. 返回401403但在响应正文中提供有用的信息,描述访问被拒绝的原因。 同样,这些信息可能比你想提供的信息多一些,以防止攻击者有所帮助。

就我个人而言,我一直使用#1的情况下有效的凭据已通过,但他们关联的帐户无权访问请求的资源。

你要求“最好的”,“正确的方式”和“正确的”,这使得回答这个问题变得困难,因为这些标准不一定是可以互换的,事实上也可能是冲突的 – 尤其是在RESTfulness 。

“最好”的答案取决于你的应用程序。 您正在构build一个简单的旧的基于浏览器(POBB)的networking应用程序? 你正在build立一个本地客户端(例如iOS或Android)并通过Web访问服务? 您是否大量使用AJAX来驱动网页更新? 卷起预定的客户?

假设您正在构build传统的Web应用程序。 让我们来看看Google是如何做到的(为简洁起见,输出已切碎):

 $ curl -v http://gmail.com/ < HTTP/1.1 301 Moved Permanently < Location: http://mail.google.com/mail/ < Content-Type: text/html; charset=UTF-8 < Content-Length: 225 < ... 

Google首先将我们redirect到GMail的“真实”URL(使用302redirect)。

 $ curl -v http://mail.google.com/mail/ < HTTP/1.1 302 Moved Temporarily < Location: https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2 < Content-Type: text/html; charset=UTF-8 < Content-Length: 352 < ... 

然后它将我们redirect到login页面(使用302redirect)。

 $ curl -v 'https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2' < HTTP/1.1 200 OK < Content-Type: text/html; charset=UTF-8 < Transfer-Encoding: chunked < ... 

login页面本身以200状态码交付

为什么这样?

从用户体验的angular度来看,如果用户转到页面,因为他们没有通过身份validation,他们无法查看,您希望将用户带到允许他们更正(通过login)的页面。 在这个例子中,login页面是独立的,只是另一个页面(这就是为什么200是合适的)。

你可以抛出一个4XX页面的解释和链接到login页面。 事实上,这可能更加RESTful。 但这是一个糟糕的用户体验。

好的,但有没有像403这样的事情是有道理的? 绝对。

但是,首先要注意的是,在规范中没有明确定义403。 为了理解它应该如何使用,你需要看看它是如何在现场实施的。

当浏览器请求目录列表(URI以“/”结尾),但服务器禁用目录列表时,403和Web服务器(如Apache和IIS)通常使用403作为浏览器返回页面的状态代码。 在这种情况下,403实际上是一个专门的404,除了让他/她知道哪里出了问题以外,用户可以做的事情不多。

但是,下面是一个站点示例,它使用403向用户发出信号,表示他/她没有足够的权限以及要采取何种措施来纠正情况(请查看完整的响应以了解详细信息):

 curl -v http://www.w3.org/Protocols/rfc2616/ < HTTP/1.1 403 Forbidden < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 1564 < ... 

(另外,在基于web的API中也可以看到403,比如Twitter的API;这里的403意思是“请求被理解了,但是它被拒绝了,一个伴随的错误信息将解释为什么。由于更新限制而被拒绝“)。

作为一种改进,我们假设您不想用户redirect到login页面,或强制用户按照指向login页面的链接。 而是希望在用户不能看到的页面上显示login表单。 如果他们成功通过身份validation,则会在页面重新加载时看到内容; 如果失败,他们会再次获得login表单。 他们从不导航到另一个URL。

在这种情况下,403的状态代码很有意义,并且与401情况是一致的,但是警告:浏览器不会popup一个要求用户authentication的对话框 – 表单在页面本身。

这种身份validation方法并不常见,但是它可能是有道理的,而且对于开发人员尝试实现的popup式JavaScript模式到login解决scheme来说,它更适合于IMHO。

这涉及到这个问题,你想redirect还是不?

附加:关于401状态码的想法…

401状态码 – 以及相关的基本/摘要authentication – 有许多事情要做。 它受到HTTP规范的支持,它受到每个主stream浏览器的支持,它本质上并不是非RESTful …问题是,从用户体验angular度来看,这是非常没有吸引力的。 如果你(或你的利益相关者/客户)能够忍受这些问题(一个大的话),那么它可能有资格成为“正确的“解决scheme。

同意。 REST只是一种风格,而不是一个严格的协议。 许多公共Web服务偏离这种风格。 你可以build立你的服务来返回你想要的。 只要确保你的客户知道如何返回代码的期望。

就个人而言,我一直使用401(未经授权)来表示未经身份validation的用户请求了需要login的资源。 然后,我要求客户端应用程序引导用户login。

我使用400(错误的请求)来响应使用无效凭据的login尝试。

HTTP 302(移动)似乎更适合于客户端是浏览器的Web应用程序。 浏览器通常在响应中遵循redirect地址。 这对于引导用户login页面很有用。

我不是在谈论HTTP身份validation,所以至less有一个状态码是我们不打算使用的(401 Unauthorized)。

错误。 401是超文本传输​​协议(RFC 2616 Fielding等)的一部分,但不限于HTTPauthentication。 此外,它是唯一的状态码,表明请求需要用户authentication。

可以使用302和200代码并且在一些情况下更容易实现,但不是全部。 如果你想服从规范,401是唯一正确的答案。

403确实是最错误的代码返回。 正如你所说的…

授权不起作用,请求不应重复。

所以这显然不适合表明授权是一种select。

我会坚持标准: 401未经授权

UPDATE

添加更多的信息,解除相关的困惑…

响应必须包含一个WWW-Authenticate头域(14.47节),其中包含一个适用于所请求资源的挑战。

如果你认为这会阻止你使用401,你必须记住还有更多的:

“字段值至less包含一个指示适用于Request-URI的authenticationscheme和参数的挑战”。

这个“指示authenticationscheme”意味着你可以selectjoin其他authenticationscheme!

HTTP协议(RFC 2616)为访问身份validationscheme定义了一个简单的框架,但是您不必使用该框架。

换句话说,你不必拘泥于通常的WWW-Auth。 你只是必须指出你的web应用程序是如何授权的,并提供标题中的相关数据,就这些了。 根据规格,使用401,你可以select自己的授权毒药! 这就是您的“webapp”在401头和您的授权实现时可以执行您想要的操作的地方。

不要让规范混淆你,认为你必须使用通常的HTTPauthenticationscheme。 你不要! 这个规范的唯一实现就是强制执行:你只需要识别你的webapp的authenticationscheme,并传递相关的参数,使请求方能够启动潜在的授权尝试。

如果你还不确定的话,我可以把所有这些都放在一个简单但是可以理解的angular度去考虑:假设你明天要发明一个新的授权scheme,那么规范也允许你使用它。 如果这些规范会限制这种新的授权技术实现的实现,那么这些规范在很久以前就会被修改。 规范定义了标准,但是它们并没有真正限制潜在的实现。

您的“TL; DR”与“TL”版本不匹配。

请求需要授权的资源的正确响应是401。

302不是正确的回应,因为实际上资源在其他地方是不可用的。 原来的URL是正确的,客户根本没有权利。 如果你按照redirect,你实际上并没有得到你想要的。 您可以投入一些与资源无关的特殊工作stream程。

403是不正确的。 403是“从这里不能到达”的错误。 你根本看不到这个,我不在乎你是谁。 有人会认为403和404是相似的。 与403不同的是,服务器说“是的,我有,但不能”,而404则说:“我对你在说什么一无所知”。 安全人士会认为404是“更安全”的。 为什么告诉他们一些他们不需要知道的东西。

您遇到的问题与REST或HTTP无关。 你的问题是试图build立客户端和服务器之间的一些有状态的关系,最终通过一些cookieperformance出来。 整个资源 – > 302 – >login页面都是关于使用被称为Web浏览器的黑客的用户体验,恰好是股票forms,糟糕的HTTP客户端和糟糕的REST参与者。

HTTP有一个授权机制。 授权标头。 在通用浏览器中的用户体验是非常糟糕的。 所以没有人使用它。

所以没有正确的HTTP响应(好,有401,但不/不能使用)。 没有适当的REST响应,因为REST通常依赖于底层协议(在这种情况下是HTTP,但是我们已经解决了这个问题)。

所以。 302 – > 200的login页面是她写的。 这就是你得到的。 如果您不使用浏览器,或者通过XHR或其他自定义客户端完成所有操作,这不会成为问题。 您只需使用授权标头,遵循HTTP协议,并使用像DIGEST或AWS使用的scheme,并完成。 那么你可以使用适当的标准来回答这样的问题。

正如你所指出的那样, 403 Forbidden被明确定义为“ 授权不会帮助 ”,但值得注意的是,作者几乎可以肯定地指的是HTTP授权(当你的站点使用不同的授权scheme)。 事实上,鉴于状态码是向用户代理而不是用户的信号,只要代理尝试提供的任何授权不会进一步协助所需的授权过程(参见401 Unauthorized ),这样的代码就是正确的。

然而,如果你从字面上理解了“ 403 Forbidden这个定义,并认为它仍然不合适,那么409 Conflict可能适用? 如RFC 2616§10.4.10中所定义的那样 :

   由于与当前冲突,请求无法完成
   资源的状态。 这个代码只允许在其中的情况
   预计用户可能能够解决冲突
   并重新提交请求。 响应主体应该包括足够的
   信息供用户识别冲突的来源。
   理想情况下,响应实体将包含足够的信息
   用户或用户代理来解决问题; 但是,这可能不是
   可能的并不是必需的。

与资源的当前状态确实存在冲突:资源处于“locking”状态,这种冲突只能通过用户提供凭据并重新提交请求来“解决”。 该机构将包括“ 用户足够的信息来识别冲突的来源 ”(它将声明,他们没有login),确实还将包括“ 用户或用户代理解决问题的足够信息 ”(即login表单)。

你的答案:

401 Unauthorized特别是如果你不在乎或不会将用户redirect到login页面

-要么-

302 Found暗示有资源,但他们需要提供凭据返回给它。 只有在您将使用redirect并确保在响应正文中提供适当的信息时才这样做。


其他build议:

401 Unauthorized通常用于处理authentication后用户无权访问的资源。

403 Forbidden对我来说是诚实的。 我从文件系统级别locking资源时使用它,并像您的post所说的,“授权不起作用”。

400 Bad Request是不合适的,因为需要login并不代表格式错误的语法。

我相信401是从失败的授权返回正确的状态代码。 参考RFC 2616部分-14.8它读取“希望使用服务器validation自己的用户代理 – 通常但不一定是在收到401响应后”