是否可以在django admin中实现"下次登录时更改密码"类型功能?

bpa*_*ker 20 python django

我希望能够在用户的设置中设置一个选项,强制他们在下次登录管理界面时更改密码.这可能吗?它将如何实施?我现在正在使用默认的auth模型,但不反对修改或更改它.谢谢你的帮助.

Chr*_*att 27

我实际上是在自己这样做的过程中.您需要三个组件:用户配置文件(如果您的站点上尚未使用),中间件组件和pre_save信号.

我的代码是在名为"accounts"的应用中.

# myproject/accounts/models.py

from django.db import models
from django.db.models import signals
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    force_password_change = models.BooleanField(default=False)

def create_user_profile_signal(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

def password_change_signal(sender, instance, **kwargs):
    try:
        user = User.objects.get(username=instance.username)
        if not user.password == instance.password:
          profile = user.get_profile()
          profile.force_password_change = False
          profile.save()
    except User.DoesNotExist:
        pass

signals.pre_save.connect(password_change_signal, sender=User, dispatch_uid='accounts.models')

signals.post_save.connect(create_user_profile_signal, sender=User, dispatch_uid='accounts.models')
Run Code Online (Sandbox Code Playgroud)

首先,我们使用User的外键创建UserProfile.该force_password_change布尔会,正如它的名字描述,无论何时你想迫使他们改变密码设置为true的用户.你可以在这里做任何事情.在我的组织中,我们还选择每90天实施一次强制性更改,因此我还有一个DateTimeField,用于存储用户上次更改密码的时间.然后在pre_save信号中设置它password_changed_signal.

第二,我们有create_user_profile_signal.这主要是为了完整性而添加的.如果您刚刚将用户配置文件添加到项目中,则需要一个post_save信号,该信号将在每次创建用户时创建UserProfile.这完成了这项任务.

第三,我们有password_changed_signal.这是一个pre_save信号,因为在此过程中,User表中的实际行尚未更新.因此,我们可以访问以前的密码和即将保存的新密码.如果两者不匹配,则表示用户已更改其密码,然后我们可以重置force_password_change布尔值.这也是重点,您可以处理您添加的任何其他内容,例如设置前面提到的DateTimeField.

最后两行将两个函数连接到适当的信号.

如果您还没有,还需要将以下行添加到项目中settings.py(更改应用程序标签和型号名称以匹配您的设置):

AUTH_PROFILE_MODULE = 'accounts.UserProfile'
Run Code Online (Sandbox Code Playgroud)

这涵盖了基础知识.现在我们需要一个中间件组件来检查force_password_change标志的状态(以及任何其他必要的检查).

# myproject/accounts/middleware.py

from django.http import HttpResponseRedirect

import re

class PasswordChangeMiddleware:
    def process_request(self, request):
        if request.user.is_authenticated() and \
            re.match(r'^/admin/?', request.path) and \
            not re.match(r'^/admin/password_change/?', request.path):

            profile = request.user.get_profile()
            if profile.force_password_change:
                return HttpResponseRedirect('/admin/password_change/')
Run Code Online (Sandbox Code Playgroud)

这个非常简单的中间件挂钩到process_request页面加载过程的阶段.它检查1)用户是否已经登录,2)他们正在尝试访问管理员中的某个页面,以及3)他们访问的页面不是密码更改页面本身(否则,您将获得无限循环重定向).如果所有这些都为真并且force_password_change标志已设置为True,则将用户重定向到密码更改页面.在更改密码(触发前面讨论的pre_save信号)之前,他们将无法在其他任何地方导航.

最后,您只需要将此中间件添加到项目中settings.py(同样,根据需要更改导入路径):

MIDDLEWARE_CLASSES = (
    # Other middleware here
    'myproject.accounts.middleware.PasswordChangeMiddleware',
)
Run Code Online (Sandbox Code Playgroud)


pgc*_*gcd 9

我使用了Chris Pratt的解决方案,稍作改动:不是使用中间件,而是为每个页面执行后续资源使用,我想我只是拦截了登录视图.

在我的urls.py中,我将其添加到我的urlpatter中:

url(r'^accounts/login/$', 'userbase.views.force_pwd_login'),
Run Code Online (Sandbox Code Playgroud)

然后我将以下内容添加到userbase.views:

def force_pwd_login(request, *args, **kwargs):
    response = auth_views.login(request, *args, **kwargs)
    if response.status_code == 302:
        #We have a user
        try:
            if request.user.get_profile().force_password_change:
                return redirect('django.contrib.auth.views.password_change')
        except AttributeError: #No profile?
            pass
    return response
Run Code Online (Sandbox Code Playgroud)

它似乎在Django 1.2上完美运行,但我没有理由相信1.3+应该有问题.


Dom*_*ger 1

来自Django 用户邮件列表上的一个线程:

这并不理想,但它应该有效(或提示某人提出更好的建议)。

为用户添加一个一对一的表,其中一个字段包含初始密码(当然是加密的,因此它看起来像表中的密码 auth_user)。

当用户登录时,让登录页面检查密码是否匹配。如果这样做,请重定向到密码更改页面而不是正常的重定向页面。