Django account_activation_token.check_token总是在constant_time_compare()中返回False

问题描述 投票:0回答:1

我有一个ActivationTokenGenerator,它创建一个令牌,用于通过电子邮件发送的帐户验证。例如,我使用参数包括timestamp,id和用户活动状态来配置它:

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


    class ActivationTokenGenerator(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 = ActivationTokenGenerator()

然后我使用account_activation_token在我用send_mail发送的验证邮件中生成令牌。

@classmethod
    def send_email(cls, request, user):
        current_site = get_current_site(request)
        mail_subject = 'Activate your Poros account.'
        message = render_to_string('email_verification.html', {
            'user': user,
            'domain': current_site.domain,
            'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
            'token': account_activation_token.make_token(user),
        })
        to_email = user.email
        email = EmailMessage(
            mail_subject, message, to=[to_email]
        )
        email.send()

所有内容看起来都是完美的电子邮件,其中包含一个令牌,其中包含一个带有这样的模式

url(r'activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        activate, name='activate'),

并在电子邮件中看起来像这样:

http://{{ domain }}{% url 'activate' uidb64=uid token=token %}

然后当点击链接时,它将调用此activate视图:

from django.http import HttpResponse

from django.contrib.auth import login

from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from accounts.utilities import account_activation_token
from accounts.models import User


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

    print(token)

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

但是activate视图总是返回激活链接无效。我试图将它追踪到account_activation_token.check_token(user, token)

我试图深入调试内部Django PasswordResetTokenGenerator我发现check_token()有步骤检查时间戳/ uid用这样的一行:

# Check that the timestamp/uid has not been tampered with
    if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
        return False

这叫做constant_time_compare

def constant_time_compare(val1, val2):
    """Return True if the two strings are equal, False otherwise."""
    return hmac.compare_digest(force_bytes(val1), force_bytes(val2))

我真的不明白这个token_check的较低层正在发生什么。解决这个问题的更好方法是什么?

python django token
1个回答
2
投票

改变这一行:

return six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active)

到这一行:

return six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.username)

它有效。我使用这种方法解决了问题。但不知道原因。

© www.soinside.com 2019 - 2024. All rights reserved.