0
0

Django Userモデル以外でパスワード認証

Posted at

DjangoでUserモデル以外にパスワードを持つモデルを定義して認証したいことがあった。

admin.py
class AdminName(admin.ModelAdmin):
    readonly_fields = ('password',) #1
    form = MyForm
    fieldsets = [
        (None, {'fields':('name',)}),
        (None, {'fields':('password',),'description':'id'}) #2
    ]

    def get_object(self, request, view, object_id):
        obj = super(AdminName, self).get_object(request,view, object_id) #3
        if obj:
            url = reverse('change_password', args=[obj.id])
            # objが存在する場合、そのidを設定します
            self.fieldsets[1][1]['description'] = '生のパスワードは格納されていないため、このパスワードを確認する方法はありません。\
            しかし'+f'<a href="{url}">このフォーム</a>'+'を使用してパスワードを変更できます。' #4
        return obj

# Register your models here.
admin.site.register(ModelName, AdminName)

#1 編集させないリードオンリーなフィールドを記述
#2 'description' で注釈をつけられる。
#3 adminサイトのchange urlに含まれるidを取得する。
#4 文字列の中にhtmlを仕込むことによりリンクを作成

forms.py
class SetPasswordForm(forms.Form):
     error_messages = {
        "password_mismatch": _("The two password fields didn't match."),
    }
    new_password1 = forms.CharField(
        label=_("New password"),
        widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
        strip=False,
        help_text=password_validation.password_validators_help_text_html(),
    )
    new_password2 = forms.CharField(
        label=_("New password confirmation"),
        strip=False,
        widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
    )
 
    def __init__(self, index, *args, **kwargs):
        self.index = index
        super().__init__(*args, **kwargs)
 
    def clean_new_password2(self):
        password1 = self.cleaned_data.get("new_password1")
        password2 = self.cleaned_data.get("new_password2")
        if password1 and password2:
            if password1 != password2:
                raise ValidationError(
                    self.error_messages["password_mismatch"],
                    code="password_mismatch",
                )
        password_validation.validate_password(password2)
        return password2

formのcleanメソッドを使用する。たくさん資料があるのでここでは説明しない。

views.py
# adminサイトのChatTypeパスワード変更
class PasswordContextMixin:
    extra_context = None
 
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({"title": self.title, **(self.extra_context or {})})
        return context
        

class PasswordResetView(FormView):
    template_name = 'my_password_change_form.html' #1
    form_class = SetPasswordForm
    success_url = reverse_lazy('password_change_done')

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['index'] = self.kwargs['index']  # Assuming you pass 'index' as a parameter in the URL
        return kwargs

    def form_valid(self, form):
        index = form.index  # Access the index from the form
        # You can perform any additional processing or validation here if needed
        # For example, you can update the user's password and log them in
        col = Model.objects.get(id=index)
        col.password = make_password(form.cleaned_data['new_password1']) #2
        col.save()
        return super().form_valid(form)

    def form_invalid(self, form):
        # Handle invalid form submission here if needed
        return super().form_invalid(form)
    

class PasswordChangeDoneView(PasswordContextMixin, TemplateView): #3
    template_name = "my_password_change_done.html"
    title = _("Password change successful")

#1 admin標準のテンプレートを基に作成
#2 djangoのmake_passwordを用いてパスワードを暗号化
#3 パスワード変更成功後のView

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0