Django, проблема активации пользователя на сайте при переходе по ссылке в письме после регистрации
столкнулся с проблемой проверки email пользователя после регистрации и активации пользователя при переходе по ссылке из email. Суть -Пользователь создается с значением is_active = False, email отправляется, переходим по ссылке и должен пользователь стать активным (is_active = True), но увы... не проходит проверку в строке if default_token_generator.check_token(user, token):...
views:
class RegisterView(CreateView):
form_class = RegisterUserForm
template_name = "registration/reg.html"
success_url = "reg-done"
def form_valid(self, form):
user = form.save(commit=False)
user.is_active = False
user.save() # Сохраните пользователя в базе данных
token = default_token_generator.make_token(user)
print(f"Generated token: {token}") # Запись токена в консоль
self.send_confirmation_email(user, token)
return super().form_valid(form)
def send_confirmation_email(self, user, token):
print(f"User PK: {user.pk}") # Запись PK пользователя в консоль
uid = urlsafe_base64_encode(force_bytes(user.pk))
print(f"uid: {uid}")
current_site = get_current_site(self.request)
mail_subject = "Активируйте свой аккаунт"
message = render_to_string(
"registration/acc_active_email.html",
{
"user": user,
"domain": current_site.domain,
"uid": uid,
"token": token,
},
)
email = EmailMultiAlternatives(mail_subject, message, to=[user.email])
email.attach_alternative(message, "text/html")
email.send()
def activate(request, uidb64, token):
try:
uid = force_str(urlsafe_base64_decode(uidb64))
print(f"Encoded uid: {uid}") # Запись закодированного uid в консоль
user = get_user_model().objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, get_user_model().DoesNotExist):
user = None
print("попали в exept и user теперь None")
if user is not None:
print(user, token)
print(uid)
if default_token_generator.check_token(user, token):
print(f"токен при активации:", token)
user.is_active = True
user.save()
return redirect("login")
else:
print(uid)
print(f"else1 токен при активации:", token)
print(f"else1 юзер при активации:", user)
return render(request, "registration/activation_invalid.html")
else:
print(f"else2 токен при активации:", token)
return render(request, "registration/activation_invalid.html")
При переходе по ссылке в письме попадаем на страничку activation_invalid.html, минуя if default_token_generator.check_token(user, token): - попадаем в else... Токены вроде совпадают, консоль выдает:
Generated token: c3mqrl-bb20a6f3280fd2176676ec33f5f631ba
User PK: 22
uid: MjI
[09/Mar/2024 16:21:23] "GET /users/reg-done HTTP/1.1" 301 0 Encoded uid: 22 test2 c3mqrl-bb20a6f3280fd2176676ec33f5f631ba else1 токен при активации: c3mqrl-bb20a6f3280fd2176676ec33f5f631ba [09/Mar/2024 16:22:40] "GET /users/activate/MjI/c3mqrl-bb20a6f3280fd2176676ec33f5f631ba/ HTTP/1.1" 200 12465 Ну и пользователь не активируется. Все перепробовал, даже ии не смог разобраться, подскажите пожалуйста в чем может быть проблема?
В общем разобрался! Может кому понадобится: Оказалось, если вызвать ошибку в функции отправки email и не дать перейти на новую страницу (типа регистрация успешна), то ссылка работать будет и соответственно пользователь активируется. То есть, при обновлении или переходе на страницу (любую) сразу при регистрации пользователь каким-то образом меняется и токен активации уже не действует. По этому я решил эту проблему следующим способом:
class RegisterView(CreateView):
form_class = RegisterUserForm
template_name = "registration/reg.html"
def form_valid(self, form):
with transaction.atomic():
user = form.save(commit=False)
user.is_active = False
user.save() # Сохраните пользователя в базе данных
token = default_token_generator.make_token(user)
print(f"Generated token: {token}") # Запись токена в консоль
self.send_confirmation_email(user, token)
messages.success(
self.request,
"Регистрация прошла успешно! Пожалуйста, проверьте свою электронную почту для активации учетной записи.",
)
return HttpResponseRedirect(
reverse("home")
)
def send_confirmation_email(self, user, token):
print(f"User PK: {user.pk}") # Запись PK пользователя в консоль
uid = urlsafe_base64_encode(force_bytes(user.pk))
print(f"uid: {uid}")
current_site = get_current_site(self.request)
mail_subject = "Активируйте свой аккаунт"
message = render_to_string(
"registration/acc_active_email.html",
{
"user": user,
"domain": current_site.domain,
"uid": uid,
"token": token,
},
)
email = EmailMultiAlternatives(mail_subject, message, to=[user.email])
email.attach_alternative(message, "text/html")
email.send()
Пришлось использовать "HttpResponseRedirect" до отправки email со ссылкой на активацию. Убрал строку "success_url = "reg-done"" соответственно. И всё замечТательно работает ))) Спасибо огромное Вам @strawdog за то, что Вы отозвались и помогли. Как все вышло -- я написал код, чтобы вновь проверить всё print-ами и вышло что допустил ошибку:
def send_confirmation_email(self, user, token):
print(f"User PK: {user.pk}") # Запись PK пользователя в консоль
uid = urlsafe_base64_encode(force_bytes(user.pk))
print(f"uid: {uid}")
current_site = get_current_site(self.request)
mail_subject = "Активируйте свой аккаунт"
message = render_to_string(
"registration/acc_active_email.html",
{
"user": user,
"domain": current_site.domain,
"uid": uid,
"token": token,
},
)
email = EmailMultiAlternatives(mail_subject, message, to=[user.email])
email.attach_alternative(message, "text/html")
email.send()
print("token во время отправки: " + token) # ошибка Конкатенации строк
print("user во время отправки: " + str(user))
Что и привело меня к ответу ))) Надеюсь кому-то понадобится, а то я неделю потратил на эту вроде как очевидную вещь, но не совсем понятную сразу.