パスワードをリセットできないのはなぜですか?

今日、そのような質問が技術サポートに寄せられました。 ユーザーはパスワード回復ページに移動し、電子メールを入力して、「復元」ボタンをクリックします。 システムは、電子メールが送信されたことを喜んで報告します。 ユーザーはメールボックスを入力しますが、ユーザーにはレターが表示されず、ユーザーは不満を感じます。



これに標準的なメッセージが続きます。「メールが正しく入力されていることを確認し、メッセージがスパムではないことを確認してください。 チェックし、助けていないことを確認しました。 私はメールサーバーに行きます-手紙は送られませんでした。



私はすべての事柄から自分自身を引き離し、テストに突進します。 復旧ページに移動し、メールアドレスを入力します。すべてが正常に完了し、パスワードをリセットするためのリンクが記載されたメールが届きます。 ユーザーのメールを入力します-沈黙。 手紙は送られません。 ログには何もありません(「完全に」という言葉から)。



その後、30分の無駄な投げ、少し困惑し、多くのわいせつな言葉が続きます。 落ち着いて、深呼吸をして、Djangoのソースコードに飛び込みます。



Password_resetは、パスワードのリセットを担当します。

非表示のテキスト
@csrf_protect def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html', subject_template_name='registration/password_reset_subject.txt', password_reset_form=PasswordResetForm, token_generator=default_token_generator, post_reset_redirect=None, from_email=None, current_app=None, extra_context=None): if post_reset_redirect is None: post_reset_redirect = reverse('password_reset_done') else: post_reset_redirect = resolve_url(post_reset_redirect) if request.method == "POST": form = password_reset_form(request.POST) if form.is_valid(): opts = { 'use_https': request.is_secure(), 'token_generator': token_generator, 'from_email': from_email, 'email_template_name': email_template_name, 'subject_template_name': subject_template_name, 'request': request, } if is_admin_site: opts = dict(opts, domain_override=request.get_host()) form.save(**opts) return HttpResponseRedirect(post_reset_redirect) else: form = password_reset_form() context = { 'form': form, } if extra_context is not None: context.update(extra_context) return TemplateResponse(request, template_name, context, current_app=current_app)
      
      







post_reset_redirectへのリダイレクトが発生するため、form.save()が実行されます。 彼のフードの下にあるものを見ます:

非表示のテキスト
 def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ from django.core.mail import send_mail UserModel = get_user_model() email = self.cleaned_data["email"] active_users = UserModel._default_manager.filter( email__iexact=email, is_active=True) for user in active_users: # Make sure that no email is sent to a user that actually has # a password marked as unusable if not user.has_usable_password(): continue if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', } subject = loader.render_to_string(subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) send_mail(subject, email, from_email, [user.email])
      
      







ここで、もちろん、それは私に来ます。 ユーザーは最初にVKontakteを通じて登録しました。 次に、メールを入れてください。 解かれたVKontakte。 そして今、彼へのVKを介した登録の過程で、すなわち ユーザーにはset_unusable_password()



が割り当てられset_unusable_password()



パスワードがないため)。



感情のこのすべての流れは、これらの行によって引き起こされました:



 # Make sure that no email is sent to a user that actually has # a password marked as unusable if not user.has_usable_password(): continue
      
      





なんで? なんで? 誰のせいですか? 元々設定されていなかったパスワードをリセットできないのはなぜですか? そして最も重要なのは、なぜシステムがこれを報告しないのに、笑ってpost_reset_redirectにリダイレクトするのか?! 彼らが言うように、「明示的は暗黙的よりも優れている」?



一般的に、覚えておいてください。 そして、この熊手を踏まないでください。



更新:



仲間のゼウスに感謝します

使用不可のパスワードでフラグが設定されたユーザー(set_unusable_password()を参照)は、LDAPなどの外部認証ソースを使用する際の誤用を防ぐためにパスワードのリセットを要求することはできません。メールも送信されません。


さて、この小さな調査に関連して、それは興味深いです。



All Articles