2015-12-08 68 views
1

目標:使用RESTful服務安全且安全地更新用戶密碼。RESTful更新密碼

我有點困惑的工作流程,採用最佳實踐,應該是什麼:
    1)更新了誰知道有現有的密碼,用戶密碼
    2)設密碼如果用戶忘記了。
    3.)URIs(資源)是RESTful嗎?爲了這個Web應用程序的目的,我只需要GET和POST進行更改。

我相信我的代碼可能是多餘的。密碼更新方法(如下所示)未正確更新密碼。它正在改變它,但是當我嘗試使用在new_password中設置的新密碼登錄時,密碼不匹配。我同樣按照Michael Merickel的這個STACKs answer來更新。

用戶= DBSession.query(用戶).filter_by(電子郵件=電子郵件)。首先() 如果用戶: user.password的= NEW_PASSWORD

謝謝你的任何見解/輸入。我是新手,想要正確編碼。

所有這一切都是通過HTML而不是JSON。
軟件:Python的2.7.9,1.5.7金字塔,SQLAlchemy的1.0.9


資源: __init__.py

config.add_route('users', '/users') 
config.add_route('user', '/users/{id:\d+}/{login}') #/{login} added login 

config.add_route('reset_password', '/users/{username}/reset_password')#reset 
config.add_route('new_password', '/users/{username}/new_password')#new 
config.add_route('save_password', '/save_password')#new 

views.py

#http://0.0.0.0:6432/users/dorisday/reset_password <--like this 
@view_config(route_name='reset_password', renderer='templates/password_recovery.jinja2') 
def forgot_password(request): 
    if request.method == 'GET': 
     username = request.params['username'] 
     if username is not None: 
      user = api.retrieve_user(username) 

     return {} 

#http://0.0.0.0:6432/users/macycat/new_password <--like this 
@view_config(route_name='new_password', request_method='GET', renderer='templates/new_password.jinja2') 
def new_password(request): 
    logged_in_userid = authenticated_userid(request) 
    if logged_in_userid is None: 
     raise HTTPForbidden() 
    user = api.retrieve_user(logged_in_userid) 
    return {'user': user.username} 

@view_config(route_name='save_password', request_method='POST', renderer='templates/new_password.jinja2') 
def save_password(request): 
    with transaction.manager: 
     logged_in_userid = authenticated_userid(request) 
     if logged_in_userid is None: 
      raise HTTPForbidden() 
     user = api.retrieve_user(logged_in_userid) 
     if 'form.submitted' in request.params: 
      password = request.params['old_password'] 
      new_password = request.params['new_password'] 
      confirm_password = request.params['confirm_password'] 
      if new_password == confirm_password: 
       continue 
       if user is not None and user.validate_password(password): #encrypted way of checking password from DB 
        user.password = new_password 

       message = 'Whoops! Passwords do not match.' 

     transaction.commit() 
     raise HTTPSeeOther(location=request.route_url('login')) 
     return {'message': message, 'new_password': new_password} 

散列密碼在SQLALCHEMY DB方案中,如下所示:

Storing and validating encrypted password for login in Pyramid

+0

你應該使用一些認證(OAuth的認證可以和它依然寧靜)擔心這個......你應該也沒有實際更改密碼,但通過電子郵件發送相關電子郵件帳戶鏈接到「更改密碼」類型的東西 –

+0

@JoranBeasley我正在使用金字塔的身份驗證代碼進行登錄。至於重置密碼,我不知道該怎麼做。你能指出我的東西是不是Django,因爲我使用SQLAlchemy和Pyramid。也許例如僞代碼?作爲藍圖,這將非常有幫助。還是鏈接?謝謝!!! – thesayhey

回答

6

1.更新密碼。

通常情況下,密碼存儲在散列形式的數據庫,因此,如果有人偷了你的數據庫,他們不能輕易得到密碼。從你的代碼中不清楚實際發生散列的位置,所以你需要檢查user.password = new_password是否執行了所需的魔法,或者是否需要手動執行。它應該類似於最初用密碼創建用戶的代碼。

的您是否獲得了「哎呦密碼不匹配'!」消息,如果你忘了行else從句前它的實際問題:

  if user is not None and user.validate_password(password): #encrypted way of checking password from DB 
       user.password = new_password 
      **else:** 
       message = 'Whoops! Passwords do not match.' 

2.密碼重置爲用戶誰不知道他們當前的密碼

一個簡單的方法是將一個新的字段,如password_reset_secret,添加到您的用戶模型。當一個健忘的人的類型在他們的電子郵件,你會發現通過電子郵件用戶,填充password_reset_secret隨機未猜測的胡言亂語,並用鏈接向用戶發送電子郵件到一個特殊的頁面,說https://yoursite.com/password_reset/jhg876jhgd87676

一旦接收到電子郵件,用戶點擊鏈接並訪問「祕密」頁面 - 這一點你知道他們有權訪問他們輸入的電子郵件地址,因爲URL是不可猜測的,並且從任何地方都沒有鏈接。在該頁面上是一個包含新密碼字段的表單。當他們輸入一個新密碼時,您從URL中查詢password_reset_secret的用戶對象並更新其密碼。完成。

要使密碼重置URL在一段時間後過期,您可以在User模型中添加另一個字段字段(比如說「password_reset_last_valid」),並在創建密碼重置哈希時將其設置爲「now + 3 days」當用戶嘗試訪問鏈接時檢查字段。如果該字段的值是過去,那麼你只是假裝沒有發現任何東西。

爲防止用戶多次使用鏈接,只需在用戶成功更改密碼後清除password_reset_secretpassword_reset_last_valid字段。

3. URI是否寧靜?

不,他們不是,但你可能不應該在這個階段:)

+0

創建用戶時,密碼在創建時自動散列。我在db中有一個'validate_password()'函數,然後驗證。看到我上面添加的鏈接。那樣有用嗎?還是應該在'new_password'代碼中添加手動代碼?你對2.密碼重置的解釋非常棒!我仍然不確定'password_reset_secret'在用戶模型中的樣子,因爲它需要向用戶發送電子郵件(文本)。我想象的視圖代碼只會要求用戶的電子郵件,如果有效的發送,ELIF錯誤消息。 PS,你的解釋非常清楚和啓發。 – thesayhey

+0

@thesayhey:「創建用戶時,密碼會在創建時自動散列」 - 所以您需要確保在設置新密碼時密碼也被散列。我想,'validate_password()'通過散列一個新密碼的副本並將其與舊存儲的散列密碼進行比較來工作,但它不會修改您分配給user.password的值,除非有一些魔法地點。在更新密碼 – Sergey

+0

後,只需在數據庫中檢查用戶的「密碼」字段的內容,不僅可以驗證我的鏈接中顯示的密碼,還可以創建時自動散列。應該在表中創建一個新的函數,就像創建方法一樣?至於第二部分,我在db中創建了一個'retrieve_user_byemail(email)'方法,通過電子郵件查詢用戶並返回用戶對象的所有用戶信息。我認爲這將是views.py中的電子郵件發送鏈接片段?如果是這樣,我不確定你提到的自動發送和亂碼部分。 – thesayhey