就 RESTful 和无状态而言,拥有诸如 /currentUser 之类的 REST 资源是不是合法?

Posted

技术标签:

【中文标题】就 RESTful 和无状态而言,拥有诸如 /currentUser 之类的 REST 资源是不是合法?【英文标题】:Is it legal to have REST resource such as /currentUser in terms of RESTful and stateless?就 RESTful 和无状态而言,拥有诸如 /currentUser 之类的 REST 资源是否合法? 【发布时间】:2017-02-22 09:26:17 【问题描述】:

就 RESTful 和无状态而言,拥有像这样的资源是非常合法的

/users/123

但是,问题是:拥有省略用户 ID 并假定它是从用户会话在服务器上隐式解析的资源是否合法?例如:

/loggedUser

当标识符为 123 的用户获得授权时,该资源将指向 /users/123。

【问题讨论】:

【参考方案1】:

选择资源定位器

使用/me/users/me/users/myself/users/current 或类似的 URI 来标识对应于经过身份验证的用户的资源从 REST 的角度来看是非常好的。根据 Roy Thomas Fielding 的论文,任何可以命名的信息都可以是资源

5.2.1.1 Resources and Resource Identifiers

REST 中信息的关键抽象是资源。任何可以命名的信息都可以是资源:文档或图像、时间服务(例如“洛杉矶今天的天气”)、其他资源的集合、非虚拟对象(例如人)等等.换句话说,任何可能成为作者超文本参考目标的概念都必须符合资源的定义。资源是到一组实体的概念映射,而不是在任何特定时间点对应于映射的实体。 [...]

当使用上面提到的 URI 时,您有一个 已验证用户 的标识符,它将始终识别 已验证用户的概念 ,无论哪个用户已通过身份验证。

无状态约束

stateless 约束与资源的识别方式无关。无状态约束是关于不在服务器端存储任何会话状态。在这种方法中,从客户端到服务器的每个请求都必须包含服务器能够理解的所有必要信息。

请参阅菲尔丁论文中的以下引用:

5.1.3 Stateless

[...] 从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。 [...]

例如,当针对需要身份验证的受保护资源时,每个请求都必须包含所有必要的数据才能正确地进行身份验证/授权


here 和 here 已经回答了类似的问题。

【讨论】:

【参考方案2】:

只要您使用来自请求的数据(在您的情况下为 HTTP 标头),就可以了。换句话说,这可能只适用于通过身份验证的用户。

【讨论】:

【参考方案3】:

是的。 ReST 服务对授权上下文进行假设是很常见的。 尽管做出这样的决定会限制该路由对登录用户以外的用户的可用性。例如,管理员可能需要为特定用户使用该服务。

ReST 端点甚至可以使用授权上下文中存在的声明。例如,为使用某种机制登录的用户返回不同的数据。

在所有 HTTP 标头中,有一些可能不适合用于定制 ReST 响应。例如,我不会使用“推荐人”。

确保在做出此类设计决策之前检查您可能拥有的任何缓存策略。

【讨论】:

它是某些指南的一部分还是只是您的经验?如果有指导意义,您能否提供一些官方文档/页面/等的参考? ReST 不是标准。这是我说的设计主题。我的回答是基于我在企业中的经验和我很久以前在面对类似问题时对该主题所做的研究。【参考方案4】:

只要您保持无国籍状态,它就是完全合法的。也就是说,您从 HTTP 请求提供的安全上下文中推断出当前用户,通常是某种令牌。

例如,您使用包含 JWT 令牌的 Authentication 标头执行 GET /current-user。服务器可以从 JWT 令牌中获取当前用户的大部分用户信息,并从数据库中完成数据并将其检索回给调用者。

我还建议不要在 URI 中使用驼峰式大小写。这对开发者来说可能是一场噩梦,而且有些服务器不区分大小写。

请注意,如果您持有服务器用户会话,正如您在问题中暗示的那样,您的 API 已经是有状态的。

【讨论】:

【参考方案5】:

正如@n00b 所说,REST 不是一个正式的标准——这可能是件好事。

最初的定义来自Roy Fielding's dissertation. - 所以如果你按照 Roy 的建议去做,你的设计就是 RESTful。人们还添加了一些其他的东西——例如,Richardson Maturity Model 是相当普遍接受的。网络上有一些公共“标准”文档,例如Microsoft's version。不过,我认为他们没有直接解决这个问题。

所以,这取决于你 - 但它的价值......

我认为 API 应该是一致且可预测的。如果我要询问有关用户的信息,我真的不喜欢有两种方法 - 一种通过 ID,另一种使用当前用户的魔术标识符。我也不喜欢将状态概念引入 API 的想法 - 通过说“在您的 API 中有一个名为 当前用户 的概念实体”,您是在引入有状态的概念,即使您使用 HTTP 标头来管理它。

因此,如果您的 RESTful API 是为客户端应用程序设计的,我认为要求该客户端管理状态并携带当前用户的 ID 是合理的。这也使您的 GET 请求始终可缓存 - 理论上您可以缓存 /users/123,但不能缓存 /loggedUser

我认为您的身份验证和授权操作(我已登录,证明我是谁,因此可以访问系统上的特定资源)与“我是用户 123”存在逻辑差异。

您可能不同意这一点的原因是,它使您的 API 更难被人类发现 - 试图弄清楚如何获取有关当前用户的信息的人必须登录,然后记住他们的用户 ID。

【讨论】:

以上是关于就 RESTful 和无状态而言,拥有诸如 /currentUser 之类的 REST 资源是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章

有符号数和无符号数在一起如何处理的

流的有状态和无状态方法

4.有状态组件和无状态组件

Spring 上下文中的有状态 bean 和无状态 bean

有状态服务和无状态服务

有状态服务和无状态服务