通过 REST API 验证/更改密码

发布于 2024-12-17 20:18:12 字数 828 浏览 0 评论 0原文

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

该表格需要当前密码、新密码以及新密码的确认。但是,我想在用户填写每个表单字段时对其进行验证。这对于 newPasswordconfirmNewPassword(客户端)来说很简单,但对于 currentPassword 则不然。当前通过 PUT /users/:id 对 User 对象执行更新。如果传递了密码参数,我会在保存之前检查 currentPassword 参数并确保其正确。然而,为了验证,我不确定最好的方法。

我还有一个 POST /users/validate - 不确定这是否是最好的。这会验证用户对象的创建和更新,但仅验证属于用户对象的字段(电子邮件用户名密码)。 currentPassword 不是其中之一。想知道如何处理这个问题。我考虑过的一些事情:

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

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

I want to change a user password via a REST API. This is not a forgotten or reset password function, but a logged in user wanting to change their password.

The form requires the current password, the new password, and a confirmation for the new password. However, I want to validate each form field as the user fills it out. This is trivial for newPassword and confirmNewPassword (client side), but not for currentPassword. Currently performing update to the User object via PUT /users/:id. If a password parameter is passed, I check for the currentPassword parameter and ensure it is correct prior to saving. However, for validation, I'm unsure of the best approach.

I also have a POST /users/validate - not sure if this is best either. This validates a User object for both create and update, but only validates fields that belong to the User object (email, username, password). currentPassword isn't one of these. Wondering how to handle this. Some things I've considered:

POST /users/check_password,
POST /users/validate (adding in validation for currentPassword if that parameter is passed, and check that currentPassword matches the users existing password) and
POST /users/:id/validate (separate validation for existing user, requiring currentPassword).

Any thoughts or advice would be greatly appreciated. My first application that only exposes functionality via REST API.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

£噩梦荏苒 2024-12-24 20:18:13

另一种选择是在用户上创建代理资源。如果您使用 HATEOAS,您可以从 user 资源链接到 user/x/pwdchange。我想澄清一下 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 视图问题域。

Another option is to create surrogate resources on user. If you're using HATEOAS you could link down to user/x/pwdchange from the user resource. And I want to clarify pwdchange is conceived as a noun/resource, not as a verb:

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)

So, in short, I'm creating a resource named 'pwdchange' that is fully compliant with a REST view of the problem domain.

放血 2024-12-24 20:18:13

您可能会想为什么需要在输入当前密码后立即对其进行验证。我还没有看到有网站这样做。其次,拥有一个仅验证某些内容的服务是完全可以的。这就是所谓的实用诗句,打败自己试图保持安静

You might think about why you need to validate the current password as soon as it's entered. I've not seen a site do that. Second, it's perfectly fine to have a service that just validates something. Its called being practical verse beating yourself up trying to be RESTFul

执笔绘流年 2024-12-24 20:18:12

首先我要指出的是,身份验证通常是在 REST 模型之外处理的。当用户提供其凭据时,他们并没有提供其帐户对象的 STate (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。我建议使用补丁。 POST 被描述为将新资源附加到列表或将数据附加到现有资源,而 PATCH 被描述为对已知 URI 处的资源进行“部分更新”。与 PUT 不同,PATCH 不必是幂等的。

I'll start by pointing out that authentication is often handled outside of a REST model. When a user provides their credentials, they are not providing a REpresentation of their account object's STate (REST); nor is the response they receive such a representation. Because the user account resource state does not include both 'current' and 'new' passwords, the provision of both a 'current' and a 'new' password in a request can never truly fit under the REST model, but professionals often describe a 'continuum' of RESTfulness, with some APIs being completely RESTful and others falling between RPC (Remote Procedure Call) and REST.

It's not uncommon to have a RESTful component of an API that handles the serving of data models, and a more RPC component of an API that handles user accounts. You get to decide between the two. If your project includes super users that manage multiple user accounts, I would suggest trying to shoe-horn that into a REST API. If each user manages only their own account, I would suggest RPC.

If you've decided to use REST for account management, then you must choose an appropriate HTTP method (GET, POST, DELETE, HEADERS, etc). Clearly you require a method that will effect a change on the server (POST, PUT, DELETE, etc). In contrast to user orbfish's conclusion above, I'm going to say that PUT would be an appropriate method, under certain restrictions.

From RFC 2616, which formally defines our HTTP methods:

"Methods can also have the property of 'idempotence' in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent. "

Idempotency here means that if we make the same request n times in a row, the state of the server under the effects of the nth request will be the same as the state of the server under the effects of the first request. User orbfish correctly notes that if we make the request:

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

and repeat it:

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

that our first request should receive a response indicating success and our second request should receive a response indicating failure. However, the idempotency of PUT only requires that the state of the server is the same following both requests. And it is: after the first request the user's password is 'b' and after the second request the user's password is 'b'.

I mentioned restrictions above. You might want to lock a user out after m attempts to change a password unsuccessfully; this would provide security against brute-force password attacks. However, this would break the idempotency of the request: send a valid password request one time and you change your password, send it m more times and the server locks you out.

By specifying the PUT method, you are telling all clients that it's safe to send a request as many times as needed. If I as a client send a PUT request and our connection is interrupted such that I don't receive your response, I know that it is safe to send my PUT through again because it is idempotent: idempotency means that if you receive both requests it will be the same to your server as just receiving one. But if you're going to lock me out for an unsuccessful request, then it isn't safe to send a second request until I know whether you have received the first.

For this reason, you might consider PATCH or POST. I would suggest using PATCH. Whereas POST is described as either appending a new resource to a list or appending data to an existing resource, PATCH is described as a 'partial update' on a resource at a known URI. And unlike PUT, PATCH need not be idempotent.

太阳公公是暖光 2024-12-24 20:18:12

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

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

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

I don't like /check_password or /validate because they're verbs; your first "update user" is better REST.

You can add the currentPassword to your User object as an unpersisted field, or as part of the Authentication header (username:password).

I would definitely change this from a PUT to a POST, though, because the same call with the same currentPassword cannot succeed twice (PUT is idempotent).

始终不够 2024-12-24 20:18:12

您正在更改用户资源的属性(即密码)。如果您使用 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(如果无效) )。

You are changing a property of the user resource (i.e., the password). If you use HTTP Basic for your authorization, you are already providing the current password, so there is no need to repeat it. I would simply PUT the entire user resource with the new password. Example:

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!"
}

The other advantage of doing it this way is that you don't necessarily need to provide the old password, as long as you are a credentialed user that has access rights to modify the user resource. Maybe you're a customer support specialist who is never supposed to ask for the customer's old password but they are requesting a password change over the phone (after they've proven to you their identity and you've proven your identity to the system).

You want to avoid using a non-idempotent request in this case (such as PUT or PATCH), as that can lead to responses whose outcomes are uncertain (suppose the server returns a 500 for a non-idempotent request... you as the client have no idea what state the server left your resource in).

EDITED TO ADD: Note that, in a RESTful app, there is no concept of being "logged in." The communication from the client to the server is entirely stateless (it's the payload and method that communicates the state). Also, there really doesn't need to be a concept of validation the way you describe it, as a request to change the state of a resource can either be met with a 200 OK (if valid) or a 400 Bad Request (if invalid).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文