问题::我正在使用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()函数,它将发送有效的激活链接。
答案 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)