2011-11-22 306 views
4

我想通過REST API更改用戶密碼。這不是一個遺忘或重置密碼功能,而是一個登錄用戶想要更改密碼。通過REST API驗證/更改密碼

該表格需要當前密碼,新密碼和新密碼確認。但是,我想驗證每個表單字段,因爲用戶填寫它。這對於newPasswordconfirmNewPassword(客戶端)而言是微不足道的,但對於currentPassword則不是。目前通過PUT /users/:id執行對用戶對象的更新。如果通過密碼參數,我檢查currentPassword參數,並確保在保存前它是正確的。但是,對於驗證,我不確定最佳方法。

我也有一個POST /users/validate - 不知道這是否是最好的。這將驗證用戶對象的創建和更新,但僅驗證屬於用戶對象的字段(emailusernamepassword)。 currentPassword不是其中之一。想知道如何處理這個。有些事情我已經考慮:

POST /users/check_passwordPOST /users/validate(添加在驗證了currentPassword如果參數傳遞,並檢查currentPassword用戶現有密碼匹配)和 POST /users/:id/validate(對於現有用戶單獨的驗證,需要currentPassword) 。

任何想法或建議將不勝感激。我的第一個應用程序只通過REST API公開功能。

回答

1

您可能會考慮爲什麼您輸入密碼時需要驗證當前密碼。我還沒有看到一個網站這樣做。其次,擁有僅僅驗證某些東西的服務是完全正確的。它被稱爲是實用的經文跳動自己試圖成爲RESTFul

+0

驗證當前密碼以防止惡意攻擊(經過身份驗證的用戶嘗試更改具有更多權限的用戶的密碼)。 – orbfish

6

我不喜歡/ check_password或/驗證,因爲它們是動詞;你的第一個「更新用戶」更好的REST。

您可以將當前密碼添加到您的用戶對象中,作爲未被執行的字段,或作爲驗證標頭(用戶名:密碼)的一部分。

但是我肯定會把它從PUT改爲POST,因爲使用同一個currentPassword的同一個調用不能成功兩次(PUT是冪等的)。

7

我將首先指出認證通常是在REST模型之外處理的。當用戶提供他們的憑證時,他們沒有提供其帳戶對象的狀態(REST)的重新呈現;他們也沒有收到這樣的表示。由於用戶帳戶資源狀態不包含「當前」和「新」密碼,因此在請求中提供「當前」和「新」密碼永遠不能真正適合REST模型,但專業人員通常會描述RESTfulness'continuum',其中一些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次連續,服務器在 th請求的影響下的狀態將與服務器在第一個請求的影響下的狀態相同。用戶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不需要是冪等的。

+1

你說PUT是冪等的,因爲「第一次請求用戶的密碼是'b',第二次請求後用戶的密碼是'b'」,儘管有實際的響應。在兩個PUT之間的情況下,另一個客戶端執行呼叫以更改密碼時,情況並非如此。在這種情況下,2個初始PUT不是冪等的。 – nimiq

+0

@nimiq:以下是我理解你的場景的方式。假設我的密碼爲'a': 1.我發出將密碼從'a'更改爲'b'的請求 2.另一客戶發出將密碼從'b'更改爲'c'的請求 3 。我重新發出我的請求,將密碼從'a'更改爲'b' 然後您的請求(1)後密碼爲'b',但請求(3)後密碼不正確。 但是這個請求仍然是冪等的,因爲如果我在一個不間斷的行中發出相同的請求一次,兩次或n次*,那麼效果是相同的。 但是,您可能還想要一個不冪等的密碼更改請求。往上看。 – JASchilz

+0

恕我直言,補丁是技術上最正確的方法。 POST用於創建「從屬」資源,這絕對不是這裏發生的事情。從理論上講,PUT是完全覆蓋一個實體的;再次,不是發生了什麼事情。至於冪等性,我認爲這隻在請求成功的情況下才有意義。因此,如果隨後的相同請求由於密碼被改變而失敗,則該請求應該被'403 Forbidden'拒絕。我的$ .02。 – broofa

1

您正在更改用戶資源的屬性(即密碼)。如果您使用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(如果無效)。

2

另一種選擇是在user上創建代理資源。如果您使用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觀點完全兼容問題領域。