目标:使用RESTful服务安全可靠地更新用户密码.
我对使用最佳实践的工作流应该是什么感到困惑:
1.)为知道现有密码的用户更新密码
2.)如果用户忘记,重置密码.
3.)URI(资源)是否RESTful?出于此Web应用程序的目的,我只需要GET和POST进行更改.
我相信我的代码可能是多余的.密码更新方法(如下所示)未正确更新密码.它正在改变它,但是当我尝试使用设置的新密码登录时new_password
,密码不匹配.我同样遵循Michael Merickel的这个STACKs答案进行更新.
user = DBSession.query(User).filter_by(email = email).first()if user:user.password = new_password
感谢您的任何见解/输入.我是新手,想要正确编码.
所有这些都是通过HTML而不是JSON.
软件:Python 2.7.9,Pyramid 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方案中的哈希密码如下所示:
存储和验证加密密码以便在Pyramid中登录
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无法猜测且无法从任何地方链接.在该页面上是一个带有新密码字段的表单.当他们输入新密码时,您可以通过password_reset_secret
URL 从DB查询User对象并更新其密码.完成.
要使密码重置URL在一定时间后过期,您可以在User
模型中添加另一个字段字段- 例如'password_reset_last_valid',在创建密码重置哈希时将其设置为"现在+ 3天"并在用户尝试访问该链接.如果该字段的值是过去那么您只是假装找不到任何内容.
为防止用户多次使用该链接,您只需在用户成功更改密码后清除password_reset_secret
和password_reset_last_valid
字段.
3. URI是否安静?
不,他们不是,但你可能不应该在这个阶段担心这个:)