会话是否真的违反RESTfulness?

在RESTful API中使用会话是否违反RESTfulness? 我已经看到了许多意见,但我不相信会议是RESTless 。 从我的观点:

  • RESTfulness不会禁止认证(否则在RESTful服务中几乎没有用处)
  • 身份验证是通过在请求中发送身份验证令牌来完成的,通常是头部
  • 这个认证令牌需要以某种方式获得,并且可能被撤销,在这种情况下,它需要被更新
  • 身份验证令牌需要服务器验证(否则不会进行身份验证)

那么会话如何违反这个规定呢?

  • 客户端,会话使用cookie来实现
  • cookies只是一个额外的HTTP头
  • 会话cookie可以在任何时候被获取和撤销
  • 会话cookie可以有一个无限的生活时间,如果需要的话
  • 会话ID(身份验证令牌)在服务器端进行验证

因此,对于客户端,会话cookie与任何其他基于HTTP头的认证机制完全相同,除了它使用Cookie头而不是Authorization或其他专有头。 如果没有会话连接到cookie值服务器端,为什么会有所作为? 只要服务器表现为 RESTful,服务器端实现就不需要关心客户端。 因此,Cookie本身不应该使API 变得无法使用,而会话只是客户端的Cookie。

我的假设是错的吗? 什么使得会话cookie 无效

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

    • REST风格:

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

      根据维基百科 。

    • 无状态约束:

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

      根据菲尔丁论文 。

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

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

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

    在我看来,饼干没有问题。 Cookie技术是一种客户端存储机制,其中存储的数据通过每个请求自动附加到Cookie标头。 我不知道这种技术存在问题的REST约束。 所以技术本身没有问题,问题在于它的使用。 菲尔丁写了一个关于他认为HTTP cookies不好的小节 。

    从我的观点:

    • RESTfulness不会禁止认证(否则在RESTful服务中几乎没有用处)
    • 身份验证是通过在请求中发送身份验证令牌来完成的,通常是头部
    • 这个身份验证令牌需要以某种方式获得,并且可能会被吊销,在这种情况下需要更新
    • 身份验证令牌需要服务器验证(否则不会进行身份验证)

    你的观点是相当稳固的。 唯一的问题是在服务器上创建身份验证令牌的概念。 你不需要这个部分。 你需要的是在客户端存储用户名和密码,并发送每一个请求。 您不需要比HTTP基本身份验证和加密连接更多地执行此操作:

    图1.可信客户端的无状态身份验证

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

    您可能需要在服务器端的内存授权缓存,使事情变得更快,因为你必须认证每一个请求。

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

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

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

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

    首先,REST不是一种宗教,不应该这样接近。 虽然RESTful服务具有优势,但只要遵循REST的原则,只要它们对您的应用程序有意义即可。

    也就是说,身份验证和客户端状态不违反REST原则。 虽然REST要求状态转换是无状态的,但这是指服务器本身。 在心里,所有的REST都是关于文件的。 无国籍背后的想法是服务器是无国籍的,而不是客户。 任何发送相同请求的客户端(相同的头文件,cookies,URI等)应该被带到应用程序中的相同位置。 如果网站通过更新这个服务器端导航变量存储了用户的当前位置和托管导航,则会违反REST。 具有相同请求信息的另一个客户端将根据服务器端状态被带到不同的位置。

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

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

    我希望这一切都有道理。 如果你还没有,你还应该查看关于具象状态传输的维基百科文章的约束部分 。 对于REST的原则究竟是什么争论和为什么,这是特别有启发性的。

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

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

    • 您尝试GET /a没有cookie
    • 你以某种方式获得授权请求
    • 你去和授权以某种方式像POST /auth
    • 你得到Set-Cookie
    • 你尝试GET /a cookie。 但是GET /a在这种情况下表现得如此呢?

    综上所述,我相信如果我们访问某个资源并且需要进行身份验证,那么我们必须在同一个资源上进行身份验证,而不是其他任何地方。

    实际上,RESTfulness只适用于资源,如统一资源标识符所示。 所以甚至谈论像REST这样的标题,cookies等等的东西是不合适的。 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,选择书签,打开编辑器等)。


    对于认证的问题,只要信息不是URI和POST有效载荷的一部分,它是通过cookies还是头来实现的,这完全与REST无关。 所以,关于无国籍,我们只是在讨论应用数据。

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

    所以,客户端跟踪用户在做什么,只发送逻辑完整的状态转换到服务器。

    HTTP事务基本访问认证不适用于RBAC,因为基本访问认证每次都使用加密的用户名:密码来标识,而RBAC中需要的是用户希望用于特定调用的角色。 RBAC不会验证用户名的权限,而是验证角色。

    你可以像下面这样进行连接:usernameRole:password,但是这是不好的做法,也是低效的,因为当一个用户有更多的角色时,认证引擎需要测试所有连接的角色,以及每次调用。 这将破坏RBAC最大的技术优势之一,即非常快速的授权测试。

    所以这个问题不能用基本的访问认证来解决。

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

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

    对我来说,通过HTTP维护会话的方式并不多。 可以使用cookie,sessionId或带有sessionId的标题。

    如果有人有另一个想法,我会很高兴听到它。

    1. 会话不是RESTless
    2. 你的意思是只有HTTP使用的REST服务,或者我得到了错误? 基于Cookie的会话只能用于自己的(!)基于http的服务! (这可能是一个问题,使用cookie,例如从移动/控制台/桌面等)。
    3. 如果为三方开发人员提供RESTful服务,请不要使用基于cookie的会话,而应使用令牌来避免安全问题。