Restrict access to reset_password form of Django in PasswordResetView in case the user is already logged in

Viewed 790

Currently, I have a user model that can access account related information based on its session. I am using the django auth PasswordResetView. The password reset form is used to reset password if the user has forgotten his/her password. But this Django view is also accessed by the user when he is already logged in.

How can I restrict the user to access this page? I cannot find solution for this problem, since it's a total abstraction and nothing is present in my views.py file.

This is how my urls.py file looks like :

from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from users import views as user_views

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('mainapp.urls')),
    path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name="login"),
    path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name="logout"),
    path('password_reset/', auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'), name="password_reset"),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'), name="password_reset_done"),
    path('password_reset_confirm/<uidb64>/<token>', auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'), name="password_reset_confirm"),
    path('password_reset_complete/', auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'), name="password_reset_complete"),
    path('change_password/', auth_views.PasswordChangeView.as_view(template_name='users/change_password.html', success_url="/"), name="password_change"),
    # path('password_change_done/done/', auth_views.PasswordChangeDoneView.as_view(template_name='users/password_change_done.html'), name="password_change_done"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

A logged in user should not be able to access password_reset_form since it is only meant when the password is forgotten and when the user is already logged in, it does not make sense for the user to access password_reset.html.

3 Answers

Multiple ways to do this; However, I think that the quickest solution would be to write a decorator:

def login_forbidden(function=None):
    actual_decorator = user_passes_test(
        lambda u: u.is_anonymous,
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

and use it to decorate the password reset views where you want to restrict access only to unauthenticated users:

path('password_reset/', login_forbidden(auth_views.PasswordResetView.as_view(template_name='users/password_reset.html')), name="password_reset")

Alternatively, you can override the actual views.

You can use {% if user.is_authenticated %} or {% if user.is_anonymous %} and put that directly in your template no need to modify the view:

{% if user.is_anonymous %}
# user is not logged in
...
{% else %}
# user is logged in
...
{% endif %}

If you really want to modify the default views, one option would be to subclass them and use them in your urls.

In your views (using UserPassesTestMixin class):

from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth.views import PasswordResetView

class MyPasswordResetView(UserPassesTestMixin, PasswordResetView):
    template_name = 'users/password_reset.html'

    # https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.is_anonymous
    def test_func(self):
        return self.request.user.is_anonymous

In your urls:

from .views import MyPasswordResetView

...
    path(
        'password_reset/', 
        MyPasswordResetView.as_view(),
        name="password_reset"),
...

You should learn to read the linked docs to find your answers. It says here:

[...] you can set any of the parameters of AccessMixin to customize the handling of unauthorized users [...]

And under AccessMixin you can find the attributes and methods to redirect unauthorized users.

Related