首页 > 解决方案 > 更新密码但无法从 django 中的更新密码登录

问题描述

更新用户密码首先从 URL 获取用户名并更新密码。

不确定此代码是否有效,因为我无法再次使用旧密码登录,即使使用更新的密码也是如此。

视图.py:

from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.contrib import auth

def change_password2(request, user_username):
    var_username =  get_object_or_404(User, username=user_username)
#getting username from url

    u = User.objects.get(username__exact=var_username)

    password = request.POST.get('password_update', False)
    u.set_password(password)
    b = u.save()

    update_session_auth_hash(request, b)  
    messages.success(request, 'Your password was successfully updated!')
    # return redirect('change_password')
    return render(request, 'accounts/change_password2.html')

更改密码2.html:

<form method="POST" action="/account/password2/">
  {% csrf_token %}
<input type="password" name="password_update">

<input type="submit" name="">
</form>

url.py

from django.urls import path

from .import views

    urlpatterns = [
        path('', views.account, name='account'),
        path('account/', views.account, name='account'),

    path('signup/', views.signup, name='signup'),
    path('password2/<slug:user_username>/', views.change_password2, name='change_password2'),

]

尝试隐身但由于缓存而不确定。

标签: pythondjango

解决方案


这里:

u = User.objects.get(username__exact=var_username)
# ...
b = u.save()
update_session_auth_hash(request, b) 

Model.save()返回None(提示:作为一般规则,在 Python 中,在原地更改对象的方法通常返回None),因此您将传递Noneupdate_session_auth_hash(). 你想要这个:

u = User.objects.get(username__exact=var_username)
u.set_password(the_new_password_here)
u.save()
update_session_auth_hash(request, u)

我不知道这是否是阻止您的代码(某种)工作的唯一原因,但这是一个明显的障碍。

现在正如我所提到的,您的代码是一团糟并且存在巨大的安全漏洞-实际上它允许任何人将其他任何人的密码更改为任何...您说这只是为了练习,但我建议您花时间阅读contrib.auth源代码以了解如何安全地做到这一点。

wrt/混乱部分:

# First point: 'user_username' is redundant to say the least,
# and since usernames can be changed you should use the user.id
# instead - or actually not use anything, cf below
#
# Second point: your view should be restricted to authenticated
# users only (using the `login_required` decorator being the
# simple and obvious way)
#
# Third point: only the admins and the (authenticated) user himself
# should be allowed to change the user's password. Since admins
# already can do this in the (django) admin, here you actually want
# to only allow the current authenticated user to change his own
# password, so you shouldn't pass the user id nor username and
# only work on `request.user`
#  
# Fourth point: this view should either test on the request
# method and only performs updates on a POST request, or
# just plain refuse any other method than POST (there's
# a decorator for this too). Remember that GET requests
# **MUST** be idempotent.


def change_password2(request, user_username):
    # this returns the User matching `user_username`
    var_username =  get_object_or_404(User, username=user_username)

    # this does the exact same thing AGAIN (so it's totally useless)
    # and actually only works by accident  - you're passing the user
    # object as argument where a username (string) is expected, 
    # and it only works because the string representation of a 
    # User is the username and the ORM lookup will force 
    # the argument to string.
    u = User.objects.get(username__exact=var_username)

    # Here you accept just anything as password, and
    # if you don't have one you'll try to use `False`
    # instead, which is probably not what you want.
    # 
    # You should actually use a Django form to validate
    # you inputs... 
    password = request.POST.get('password_update', False)

    u.set_password(password)

ETC...


推荐阅读