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

时间:2011-05-20 06:13:09

标签: session rest cookies restful-authentication

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

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

那么会话如何违反这个?

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

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

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

8 个答案:

答案 0 :(得分:321)

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

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

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

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

我希望所有这一切都有道理。如果您还没有,请查看Constraints sectionwikipedia article on Representational State Transfer。关于REST的原则实际上是在争论什么以及为什么这一点,这一点尤其具有启发性。

答案 1 :(得分:279)

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

  • 的RESTful:

      

    可以表征符合REST约束的应用程序   在本节中描述为“RESTful”。[15]如果服务违反任何规定   对于所需的约束,它不能被认为是RESTful。

    根据wikipedia

  • 无国籍约束:

      

    我们接下来为客户端 - 服务器交互添加一个约束:   沟通必须是无国籍的,就像在   第3.4.3节(图5-3)的客户端无状态服务器(CSS)样式,   这样从客户端到服务器的每个请求都必须包含所有   理解请求所必需的信息,不能采取   服务器上任何存储上下文的优点。会话状态是   因此完全留在客户端。

    根据Fielding dissertation

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

  

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

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

在我看来,cookies没有任何问题。 cookie技术是一种客户端存储机制,其中存储的数据通过每个请求自动附加到cookie头。我不知道REST约束对这种技术有问题。因此技术本身没有问题,问题在于其使用。 Fielding wrote a sub-section关于他认为HTTP cookie不好的原因。

  

从我的观点来看:

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

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

Figure 1. - Stateless authentication by trusted clients

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

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

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

Figure 2. - Stateless authentication by 3rd party clients

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

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

答案 2 :(得分:12)

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

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

  • 您尝试GET /a无Cookie
  • 以某种方式获得授权请求
  • 你去授权POST /auth
  • 你得到Set-Cookie
  • 您使用 Cookie尝试GET /a 。但GET /a在这种情况下是否表现得很明显?

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

答案 3 :(得分: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状态。每个州都可以完全 通过它包含的表示和一组表达来理解 它提供的过渡,过渡限于a 统一的行动是可以理解的。系统可能是 一个复杂的状态图,但每个用户代理只能看到 一次一个状态(当前稳态),因此每个状态 状态简单,可以独立分析。用户,OTOH, 能够随时创建自己的过渡(例如,输入 URL,选择书签,打开编辑器等。)“


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

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

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

答案 4 :(得分:1)

HTTP事务,基本访问身份验证不适用于RBAC,因为基本访问身份验证使用加密的用户名:密码每次都要识别,而RBAC中需要的是用户想要用于特定呼叫的角色。 RBAC不会验证用户名的权限,而是验证角色的权限。

你可以这样连接:usernameRole:password,但这是不好的做法,而且效率也很低,因为当用户拥有更多角色时,身份验证引擎需要在连接中测试所有角色,并且每个重拨。这将破坏RBAC最大的技术优势之一,即非常快速的授权测试。

因此使用基本访问身份验证无法解决问题。

要解决这个问题,会话维护是必要的,根据一些答案,这似乎与REST相矛盾。

这就是我喜欢REST不应被视为宗教的答案。例如,在复杂的商业案例中,在医疗保健领域,RBAC绝对是常见且必要的。如果他们不被允许使用REST将是一个遗憾,因为所有REST工具设计师都会将REST视为宗教。

对我而言,通过HTTP维护会话的方法并不多。可以使用带有sessionId的cookie,或带有sessionId的头。

如果有人有其他想法,我会很高兴听到它。

答案 5 :(得分:0)

我认为令牌必须包含编码在其中的所有必需信息,这可以通过验证令牌并解码信息来进行身份验证 https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/

答案 6 :(得分:-1)

否,使用会话不一定违反RESTfulness。如果您遵守REST的规定和约束,那么使用会话将完全多余。

答案 7 :(得分:-4)

  1. 会话不是RESTless
  2. 你的意思是REST服务仅供http使用,还是我的错误?基于Cookie的会话必须仅用于自己的(!)基于http的服务! (使用cookie可能会出现问题,例如从Mobile / Console / Desktop /等。)
  3. 如果您为3d party开发人员提供RESTful服务,请不要使用基于cookie的会话,而是使用令牌来避免安全问题。