分析

在allauth中,默认重置密码的方式是用户发送重置密码的请求后,发送重置密码的链接到用户的邮箱里面,如下图所示,用户点击此链接就可以修改与该邮箱绑定的账号的密码。但是这样存在一个问题,如果使用QQ邮箱的SMTP服务,一天最多只能发送50封邮件,这样是明显不满足需求的。而如果为了实现此功能去部署一台邮件服务器或者申请一个企业邮箱,动辄几千一年的费用实在伤不起。所以在中小型的项目中,有一种折中的方法,即用户通过输入自己的身份证即可重置对应的账号密码。

allauth默认的重置密码方式

重写form表单

allauth中的重置密码的类视图位于allauth.account.views.PasswordResetView,我们需要在views.py中继承这个类并且重写它的post方法。

class CustomPasswordResetView(PasswordResetView):

    def post(self, request, *args, **kwargs):
        reset_password_form = ResetPasswordForm(request.POST)
        if reset_password_form.is_valid():
            # 取到身份证之后取到用户对象
            identity_card = reset_password_form.cleaned_data['identity_card']
            username = UserProfile.objects.get(
                identity_card=identity_card)
            user = User.objects.get(username=username)
            # 生成token
            token_generator = kwargs.get(
                "token_generator", default_token_generator)
            temp_key = token_generator.make_token(user)
            path = reverse(
                "account_reset_password_from_key",
                kwargs=dict(uidb36=user_pk_to_url_str(user), key=temp_key),
            )
            url = build_absolute_uri(request, path)
            # 重定向至修改密码链接
            return redirect(url)
        else:
            return render(request, 'account/identity_card_error.html')

同时在form.py中也添加下面的内容

# 重写重置密码表单
class ResetPasswordForm(forms.Form):

    """
    重置密码表单,要求验证身份证
    """
    identity_card = forms.CharField(
        label='身份证号码',
        max_length=18,
        required=True)

    def clean_identity_card(self):
        # 取到身份证号码
        identity_card = self.cleaned_data["identity_card"]
        # 在UserProfile中筛选符合条件的用户,返回用户名
        # 如果用get方法的话取不到会直接报错,所以用filter方法
        # 同样的,身份证需要设置UNIQUE
        username = UserProfile.objects.filter(
            identity_card=identity_card)
        if not username:
            raise forms.ValidationError(
                _("身份证不存在")
            )
        return self.cleaned_data["identity_card"]

    def save(self, request, **kwargs):
        return self.cleaned_data['identity_card']

随后在settings.py中写入以下配置

ACCOUNT_FORMS = ({
    'reset_password': 'UserProfile.forms.ResetPasswordForm',
})

再在templates/account/目录下新建indentity_card_error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>身份证不存在!</h3>
    <a href="/accounts/password/reset/">返回</a>
</body>
</html>

进入http://127.0.0.1:8000/accounts/password/reset/即可通过输入身份证号码重置密码

重置密码界面

设置新密码界面

当身份证不存在时,会直接返回错误信息

Last modification:January 5th, 2021 at 10:44 pm