Django PasswordResetTokenGenerator,check_token(user,token)在生产时返回False,在本地正常运行

时间:2019-02-19 13:52:50

标签: python django amazon-ec2

问题::我正在使用Django内置类“ PasswordResetTokenGenerator”生成令牌,用于用户帐户激活链接,该链接在提交RegistrationForm后通过电子邮件发送给用户。(我使用Celery和RabbitMQ用于任务执行和消息排队)

views.py(RegistrationView)

class MyUserCreationView(FormView):
    template_name = 'accounts/auth/register.html'
    form_class = MyUserCreationForm

    def form_valid(self, form):
        user = form.save(commit=False)
        user.is_active = False
        email = user.email
        user.save()
        current_site = str(get_current_site(self.request))
        confirm_mail.apply_async((user.username, current_site), countdown=5)
        return render(self.request, 'accounts/auth/register.html', {'email': email})

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six

class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp)+ six.text_type(user.is_active)

        )

account_activation_token = TokenGenerator()

tasks.py(Celery任务)向用户发送电子邮件

from django.core.mail import send_mail
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.shortcuts import get_object_or_404

from celery import task

from ecommerce.settings.base import EMAIL_HOST_USER
from account.tokens import  account_activation_token

@task
def confirm_mail(user_name, current_site):

    user_obj = get_object_or_404(User,username=user_name)
    token=account_activation_token.make_token(user_obj)

    subject = 'Activate your MissIndia account.'
    message = render_to_string(
        'email/acc_activate_email.html',
        {
            'user': user_obj,
            'domain': current_site,
            'uid': urlsafe_base64_encode(force_bytes(user_obj.pk)).decode(),
            'token': token,
        }
    )

    mail_sent = send_mail(subject, message, EMAIL_HOST_USER, [
                        user_obj.email], fail_silently=False)

    return mail_sent

urls.py

from django.urls import path, re_path
from . import views
app_name = 'accounts'
urlpatterns = [
    re_path('confirm-email/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', views.activate, name='activate'),
]

views.py (激活帐户)

def activate(request, uidb64, token):
    try:
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None

    if user is not None and account_activation_token.check_token(user, token):
        user.is_active = True
        user.save()
        # login(request, user)
        # return redirect('home')
        return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
    else:
        return HttpResponse('Activation link is invalid!')
  

注意::通过在我的EC2实例中使用SSH,如果我使用Django shell命令在task.py中执行了Confirm_mail()函数,它将发送有效的激活链接。

2 个答案:

答案 0 :(得分:0)

在django较新版本中,django.utils.six被删除 也许您在本地开发中使用较低版本,而在生产中使用较高版本 如果您是这种情况,则必须选择修复它,并都使用相同的django旧版本 或者只是在终端上做: pip3安装六 然后在INSTALLED_APPS中的settings.py中添加到列表中: '六', 现在要导入它而不是django.utils导入六个,您将要做的

import six

直接

答案 1 :(得分:0)

最后,我通过在视图中生成令牌并将其作为参数传递给celery任务而不是在Celery Task中生成令牌来解决此问题。

查看代码。

class MyUserCreationView(FormView):
template_name = 'accounts/auth/register.html'
form_class = MyUserCreationForm

def form_valid(self, form):
    # This method is called when valid form data has been POSTed.
    # It should return an HttpResponse.
    user = form.save(commit=False)
    user.is_active = False
    email = user.email
    settings = SiteSettings.load()
    if settings.other_mail not in ('', None) and settings.domain not in ('', None):
        user.save()
        token = account_activation_token.make_token(user)
        confirm_mail.delay(settings.other_mail,
                           user.username, settings.domain, token)

        messages.add_message(self.request, messages.WARNING,
                             'We have sent an email with a confirmation link to your email address. Please allow 5-10 minutes for this message to arrive.', extra_tags='success')

        return render(self.request, 'accounts/auth/register.html', {'email': email})

    messages.add_message(self.request, messages.WARNING,
                         'Account not created, due to invalid site settings! Please Contact Admin.', extra_tags='danger')

    return render(self.request, 'accounts/auth/register.html')

Celery任务

@app.task
def confirm_mail(from_mail, user_name, current_site, token):
    ses = AwsSes()
    user_obj = get_object_or_404(User, username=user_name)
    html_content = render_to_string(
        'email/acc_activate_email.html',
        {
            'user': user_obj,
            'confirm_link': urljoin(current_site, reverse('accounts:activate', args=[urlsafe_base64_encode(force_bytes(user_obj.pk)).decode(), token])),
        }
    )
    return ses.send_mail(from_mail, user_obj.email, 'Account activation.', html_content)