会话真的违反了R​​ESTfulness吗?

dec*_*eze 472 cookies rest session restful-authentication

在RESTful API中使用会话是否真的违反了R​​ESTfulness?我看到很多意见朝着两个方向发展,但我不相信会话是无REST的.在我看来,我的观点是:

  • RESTfulness不禁止身份验证(否则在RESTful服务中几乎没有用)
  • 通过在请求中发送身份验证令牌(通常是标头)来完成身份验证
  • 此身份验证令牌需要以某种方式获取并可能被撤销,在这种情况下需要续订
  • 验证令牌需要由服务器验证(否则它不会是身份验证)

会话如何违反这一点?

  • 客户端,会话使用cookie实现
  • cookies只是一个额外的HTTP标头
  • 可以随时获取和撤销会话cookie
  • 如果需要,会话cookie可以有无限的生命周期
  • 会话ID(身份验证令牌)在服务器端验证

因此,对于客户端,会话cookie与任何其他基于HTTP头的身份验证机制完全相同,除了它使用Cookie头而不是Authorization其他专有头.如果cookie值服务器端没有附加会话,为什么会产生影响呢?只要服务器表现为 RESTful ,服务器端实现就不需要关注客户端.因此,cookie本身不应该使API无REST,而会话只是客户端的cookie.

我的假设是错的吗?什么使会话cookie RESTless

Jar*_*ing 328

首先,REST不是宗教,不应该这样接近.虽然RESTful服务有一些优点,但只要对应用程序有意义,就应该遵循REST的原则.

也就是说,身份验证和客户端状态不违反REST原则.虽然REST要求状态转换是无状态的,但这指的是服务器本身.从本质上讲,REST的所有内容都与文档有关.无国籍状态背后的想法是SERVER是无状态的,而不是客户端.发出相同请求的任何客户端(相同的标头,cookie,URI等)应该被带到应用程序中的相同位置.如果网站通过更新此服务器端导航变量来存储用户的当前位置和托管导航,则将违反REST.具有相同请求信息的另一个客户端将根据服务器端状态被带到不同的位置.

Google的Web服务是RESTful系统的绝佳示例.它们需要一个带有用户身份验证密钥的身份验证标头,以便在每次请求时传递.这确实略微违反了REST原则,因为服务器正在跟踪身份验证密钥的状态.必须维护此密钥的状态,并且它具有某种到期日期/时间,之后它不再授予访问权限.但是,正如我在帖子顶部提到的那样,必须做出牺牲以允许应用程序实际工作.也就是说,身份验证令牌必须以允许所有可能的客户端在其有效时间内继续授予访问权限的方式存储.如果一台服务器正在管理身份验证密钥的状态,以至于另一台负载均衡的服务器无法接管基于该密钥的请求,那么您已经开始真正违反REST的原则.Google的服务可以确保您可以随时将您在手机上使用的身份验证令牌与服务器A进行负载均衡,并从桌面访问负载均衡服务器B,并且仍然可以访问系统并转到相同的资源,如果请求是相同的.

这一切归结为您需要确保您的身份验证令牌针对某种类型的后备存储(数据库,缓存等)进行验证,以确保您保留尽可能多的REST属性.

我希望所有这一切都有道理.您还应该查看维基百科关于具象状态转移的文章中约束条款(如果您还没有).关于REST的原则实际上在争论什么以及为什么,这一点尤其具有启发性.

  • 我听过很多讲道,会议不安宁.如果您尝试构建Web应用程序,HTTP基本身份验证是一个真正的倒退. (9认同)
  • 我会改写你的初步陈述.如果REST的约束能够理解您的应用程序,则只使用REST.您可以自由应用这些约束的子集,您将获得一部分好处.但是,此时您已经创建了自己的建筑风格.这不是一件坏事,事实上这就是罗伊论文前四章的原则设计.REST只是一个例子. (6认同)
  • 由于到目前为止还没有其他论点,我接受这个写得很好的回复.我认为重要的部分是*无状态服务器*并不意味着*无状态服务器*,我认为经常被误解或误用.服务器可以(并且通常*必须*)具有它想要的任何状态,只要它表现为*幂等*. (6认同)
  • @Darrel一个公平的观点.老实说,我不确定Google是如何做到这一点的,但过期时间可以编码到身份验证令牌中.我相信我的更大观点仍然有效.有一些类型的状态只需要维护,只要你理解*为什么*REST要求无状态,你可以以一种有意义的方式违反它,对系统的其余部分产生许多影响,并且有一个优点. RESTful架构. (4认同)

inf*_*rno 290

首先,让我们定义一些术语:

  • REST风格:

    可以将符合本节中描述的REST约束的应用程序表征为"RESTful".[15] 如果服务违反任何所需的约束,则不能将其视为RESTful.

    根据维基百科.

  • 无国籍约束:

    接下来我们为客户端 - 服务器交互添加一个约束:通信本质上必须是无状态的,如3.4.3节(图5-3)的客户端无状态服务器(CSS)样式,这样每个请求从客户端到服务器必须包含理解请求所需的所有信息,并且不能利用服务器上任何存储的上下文.因此,会话状态完全保留在客户端上.

    根据菲尔丁的论文.

因此,服务器端会话违反了REST的无状态约束,因此RESTfulness也是如此.

因此,对于客户端,会话cookie与任何其他基于HTTP头的身份验证机制完全相同,除了它使用Cookie头而不是授权或其他专有头.

通过会话cookie,您可以将客户端状态存储在服务器上,因此您的请求具有上下文.让我们尝试将负载均衡器和另一个服务实例添加到您的系统中.在这种情况下,您必须共享服务实例之间的会话.很难维护和扩展这样的系统,所以它的规模很大......

在我看来,cookies没有任何问题.cookie技术是一种客户端存储机制,其中存储的数据通过每个请求自动附加到cookie头.我不知道REST约束对这种技术有问题.因此技术本身没有问题,问题在于其使用.菲尔丁写了一个小节,说明为什么他认为HTTP cookie是坏的.

在我看来,我的观点是:

  • RESTfulness不禁止身份验证(否则在RESTful服务中几乎没有用)
  • 通过在请求中发送身份验证令牌(通常是标头)来完成身份验证
  • 此身份验证令牌需要以某种方式获取并可能被撤销,在这种情况下需要续订
  • 验证令牌需要由服务器验证(否则它不会是身份验证)

你的观点非常可靠.唯一的问题是在服务器上创建身份验证令牌的概念.你不需要那个部分.您需要的是在客户端上存储用户名和密码,并在每次请求时发送它.除HTTP基本身份验证和加密连接之外,您不需要执行此操作:

图1.  - 受信任客户端的无状态身份验证

  • 图1. - 受信任客户端的无状态身份验证

您可能需要在服务器端使用内存中的auth缓存来加快速度,因为您必须对每个请求进行身份验证.

现在,由您所信赖的客户可以很好地工作,但第三方客户呢?他们不能拥有用户名和密码以及用户的所有权限.因此,您必须单独存储第三方客户端可以由特定用户拥有的权限.因此,客户端开发人员可以注册他们的第三方客户端,并获得唯一的API密钥,用户可以允许第三方客户端访问其部分权限.喜欢阅读姓名和电子邮件地址,或列出他们的朋友等...在允许第三方客户端之后,服务器将生成访问令牌.第三方客户端可以使用这些访问令牌来访问用户授予的权限,如下所示:

图2.  - 第三方客户端的无状态身份验证

  • 图2. - 第三方客户端的无状态身份验证

因此,第三方客户端可以从受信任的客户端(或直接从用户)获取访问令牌.之后,它可以使用API​​密钥和访问令牌发送有效请求.这是最基本的第三方身份验证机制.您可以在每个第三方认证系统的文档中阅读有关实现细节的更多信息,例如OAuth.当然,这可能更复杂,更安全,例如,您可以在服务器端签署每个请求的详细信息,并将签名与请求一起发送,等等......实际的解决方案取决于您的应用程序的需要.

  • 我不明白为什么每个人似乎都接受您应该在客户端存储密码并随每个请求发送它们的评论。这是一种非常糟糕的做法,会危及客户的敏感数据。未散列的密码(必须一遍又一遍地发送)不应存储在任何地方。如果我们接受这一点,那么您将像大多数身份验证系统一样使用令牌,在这种情况下,我们用于扩展令牌存储库的任何机制都将具有与任何会话可扩展性几乎相同的可扩展性问题。 (11认同)
  • 是的,你完全正确.自从我发布这个问题以来,我已经完全看到了这一点.在查看技术细节时,会话cookie并不是特别的,但是它缺少树木的森林.由于漂亮的图表,接受了你的答案.;) (4认同)
  • @ inf3rno,完全RESTful服务确实不能依赖会话cookie进行身份验证,就像传统方式一样.但是,如果cookie包含服务器稍后需要的所有状态信息,则可以使用cookie执行身份验证.您还可以通过使用公钥/私钥对进行签名来确保cookie不被篡改.请参阅下面的评论. (2认同)
  • @SiminJie 我认为你必须问自己是否真的需要 REST API。这通常不是合理的解决方案。我的意思是,有很多限制是大多数开发人员不理解或不关心的。它需要大量的学习才能正确地做到这一点,并且只有真正的大型服务才值得付出努力的优势。做你已经理解的事情并通过一个爱好项目尝试一下会容易得多。 (2认同)

sta*_*ort 12

Cookie不用于身份验证.为什么重新发明轮子?HTTP具有设计良好的身份验证机制.如果我们使用cookie,我们只会使用HTTP作为传输协议,因此我们需要创建自己的信令系统,例如,告诉用户他们提供了错误的身份验证(使用HTTP 401会不正确,因为我们可能不会提供Www-Authenticate给客户端,因为HTTP规范要求:)).还应该指出,这Set-Cookie只是对客户的建议.其内容可能已保存,也可能未保存(例如,如果禁用了cookie),而Authorization每次请求都会自动发送标头.

另一点是,要获得授权cookie,您可能希望先在某处提供您的凭据?如果是这样,那么它不会是RESTless吗?简单的例子:

  • 你尝试GET /a没有cookie
  • 你以某种方式获得授权请求
  • 你去授权不知何故 POST /auth
  • 你得到 Set-Cookie
  • 你尝试GET /a 使用 cookie.但GET /a在这种情况下确实表现得很明显吗?

总而言之,我相信如果我们访问某些资源并且我们需要进行身份验证,那么我们必须在同一资源上进行身份验证,而不是在其他任何地方进行身份验证.

  • 不带 cookie 的 GET /a 和带 cookie 的 GET /a 显然是两个“不同”的请求,并且它们的行为不同是可以接受的。 (7认同)

Ken*_*son 7

实际上,RESTfulness仅适用于资源,如通用资源标识符所示.所以甚至谈论关于REST的标题,cookie等内容并不合适.REST可以在任何协议上运行,即使它恰好通过HTTP进行.

主要的决定因素是:如果你发送一个REST调用,这是一个URI,那么一旦调用成功到达服务器,该URI就会返回相同的内容,假设没有执行转换(PUT,POST,DELETE) ?此测试将排除返回的错误或身份验证请求,因为在这种情况下,请求尚未进入服务器,这意味着将返回与给定URI对应的文档的servlet或应用程序.

同样,在POST或PUT的情况下,您是否可以发送给定的URI /有效负载,无论您发送消息多少次,它都将始终更新相同的数据,以便后续的GET将返回一致的结果?

REST是关于应用程序数据的,而不是关于传输数据所需的低级信息.

在下面的博文中,Roy Fielding总结了整个REST的想法:

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841

"一个RESTful系统从一个稳态进入下一个,每个这样的稳态都是一个潜在的开始状态和一个潜在的最终状态.也就是说,一个RESTful系统是一个未知数量的组件服从一个简单的一组这些规则使得它们总是在REST或从一个RESTful状态转换到另一个RESTful状态.每个状态可以通过它包含的表示和它提供的转换集完全理解,转换限于统一系统可能是一个复杂的状态图,但每个用户代理只能一次看到一个状态(当前的稳态),因此每个状态都很简单,可以独立分析.用户OTOH可以随时创建自己的过渡(例如,输入URL,选择书签,打开编辑器等)."


谈到身份验证问题,无论是通过cookie还是头文件完成,只要信息不是URI和POST有效负载的一部分,它根本就与REST无关.因此,关于无国籍,我们只讨论应用程序数据.

例如,当用户将数据输入GUI屏幕时,客户端将跟踪已输入的字段,哪些字段未输入,缺少任何必填字段等.这是所有客户端上下文,不应发送或跟踪由服务器.发送到服务器的内容是需要在IDENTIFIED资源中(通过URI)修改的完整字段集,以便在该资源中从一个RESTful状态转换到另一个RESTful状态.

因此,客户端会跟踪用户正在做什么,并且只向服务器发送逻辑上完整的状态转换.

  • 我不知道这对于提出的问题有何启示. (3认同)