6

我想通过 REST API 更改用户密码。这不是忘记或重置密码功能,而是登录用户想要更改密码。

该表单需要当前密码、新密码和对新密码的确认。但是,我想在用户填写时验证每个表单字段。newPassword这对于and (客户端)来说是微不足道的confirmNewPassword,但对于currentPassword. 当前通过 对用户对象执行更新PUT /users/:id。如果传递了密码参数,我会检查currentPassword参数并确保在保存之前它是正确的。但是,为了验证,我不确定最好的方法。

我也有一个POST /users/validate- 不确定这是否是最好的。这将验证 User 对象的创建和更新,但仅验证属于 User 对象 ( email, username, password) 的字段。currentPassword不是其中之一。想知道如何处理这个问题。我考虑过的一些事情:

POST /users/check_password, POST /users/validate(如果传递了该参数,则添加对 currentPassword 的验证,并检查 currentPassword 是否与用户现有密码匹配)和 POST /users/:id/validate(对现有用户的单独验证,要求currentPassword)。

任何想法或建议将不胜感激。我的第一个仅通过 REST API 公开功能的应用程序。

4

5 回答 5

8

我将首先指出身份验证通常在 REST 模型之外处理。当用户提供他们的凭据时,他们没有提供他们帐户对象的状态 (REST) 的表示;他们收到的回应也不是这样的表示。由于用户帐户资源状态不包括“当前”和“新”密码,因此在请求中同时提供“当前”和“新”密码永远无法真正适合 REST 模型,但专业人士经常描述RESTful 的“连续统一体”,一些 API 完全是 RESTful,而另一些则介于 RPC(远程过程调用)和 REST 之间。

处理数据模型服务的 API 的 RESTful 组件和处理用户帐户的 API 的更多 RPC 组件并不少见。你可以在两者之间做出决定。如果您的项目包含管理多个用户帐户的超级用户,我建议尝试将其硬塞到 REST API 中。如果每个用户只管理自己的帐户,我建议使用 RPC。

如果您决定使用 REST 进行帐户管理,那么您必须选择适当的 HTTP 方法(GET、POST、DELETE、HEADERS 等)。显然,您需要一种会影响服务器更改的方法(POST、PUT、DELETE 等)。与上述用户 orbfish 的结论相反,我要说 PUT 在某些限制下是一种合适的方法。

来自RFC 2616,它正式定义了我们的 HTTP 方法:

“方法还可以具有‘幂等性’,因为(除了错误或过期问题)N > 0 个相同请求的副作用与单个请求相同。方法 GET、HEAD、PUT 和 DELETE 共享这个属性。另外,方法 OPTIONS 和 TRACE 不应该有副作用,因此本质上是幂等的。

这里的幂等性意味着如果我们连续n次发出相同的请求,那么服务器在第n次请求的影响下的状态将与服务器在第一次请求的影响下的状态相同。用户 orbfish 正确地指出,如果我们提出请求:

PUT /users/:id/account {current-password: 'a', new-password: 'b'}

并重复:

PUT /users/:id/account {current-password: 'a', new-password: 'b'}

我们的第一个请求应该收到一个表明成功的响应,而我们的第二个请求应该收到一个表明失败的响应。但是,PUT 的幂等性只要求服务器的状态在两个请求之后相同。它是:在第一次请求之后,用户的密码是'b',在第二次请求之后,用户的密码是'b'。

我在上面提到了限制。您可能希望在m次尝试更改密码失败后锁定用户;这将提供针对暴力密码攻击的安全性。但是,这会破坏请求的幂等性:发送一次有效的密码请求,您更改密码,再发送m次,服务器将您锁定。

通过指定 PUT 方法,您告诉所有客户端可以安全地根据需要多次发送请求。如果我作为客户端发送 PUT 请求并且我们的连接被中断,以至于我没有收到您的响应,我知道再次发送我的 PUT 是安全的,因为它是幂等的:幂等性意味着如果您收到两个请求,它将与您的服务器一样,只是接收一个。但是如果你因为一个不成功的请求而将我锁在外面,那么在我知道你是否收到第一个请求之前,发送第二个请求是不安全的。

出于这个原因,您可能会考虑 PATCH 或 POST。我建议使用 PATCH。POST 被描述为将新资源附加到列表或将数据附加到现有资源,而 PATCH 被描述为对已知 URI 的资源的“部分更新”。与 PUT 不同,PATCH 不必是幂等的。

于 2015-01-06T20:58:48.913 回答
7

我不喜欢 /check_password 或 /validate 因为它们是动词;您的第一个“更新用户”是更好的 REST。

您可以将 currentPassword 作为非持久字段或作为 Authentication 标头(用户名:密码)的一部分添加到您的 User 对象。

不过,我肯定会将其从 PUT 更改为 POST,因为具有相同 currentPassword 的相同调用不能成功两次(PUT 是幂等的)。

于 2014-01-06T20:32:21.073 回答
2

您正在更改用户资源的属性(即密码)。如果您使用 HTTP Basic 进行授权,则您已经提供了当前密码,因此无需重复。我会简单地将整个用户资源与新密码一起放置。例子:

PUT /users/fiddlerpianist HTTP/1.1
Content-Type: application/json
Authorization: Basic ZmlkZGxlcnBpYW5pc3Q6bXlub3Rzb2F3ZXNvbWVvbGRwYXNzd29yZA==

{
    "password": "My awesome new password that no one will ever be able to guess!"
}

这样做的另一个好处是,您不必提供旧密码,只要您是具有修改用户资源的访问权限的凭证用户。也许您是一位客户支持专家,他应该要求客户提供旧密码,但他们要求通过电话更改密码(在他们向您证明了他们的身份并且您已经向系统证明了您的身份之后) .

您希望避免在这种情况下使用非幂等请求(例如 PUT 或 PATCH),因为这可能导致结果不确定的响应(假设服务器为非幂等请求返回 500 ......客户端不知道服务器将您的资源留在什么状态)。

编辑添加:请注意,在 RESTful 应用程序中,没有“登录”的概念。从客户端到服务器的通信完全是无状态的(它是传递状态的有效负载和方法)。此外,实际上不需要像您描述的那样有验证的概念,因为更改资源状态的请求可以通过 200 OK(如果有效)或 400 Bad Request(如果无效)来满足)。

于 2015-01-09T03:57:06.093 回答
2

另一种选择是在user. 如果您使用的是 HATEOAS,您可以链接到user/x/pwdchange资源user。我想澄清pwdchange的是,它被视为名词/资源,而不是动词:

GET /user/jsmith/pwdchange     List of password change requests (history)
POST /user/jsmith/pwdchange    Create password change request, return id=1
GET /user/jsmith/pwdchange/1   Get password change resource, which would
                               include the outcome (success, failure, etc)

因此,简而言之,我正在创建一个名为“pwdchange”的资源,它完全符合问题域的 REST 视图。

于 2016-03-29T13:15:54.117 回答
1

您可能会想到为什么需要在输入当前密码后立即对其进行验证。我还没有看到一个网站这样做。其次,拥有一个只是验证某些东西的服务是非常好的。它被称为是实用的诗句打败自己试图成为 RESTFul

于 2011-11-23T12:57:40.707 回答