简体   繁体   中英

How to prevent users from seeing data that does not belong to them in Django DetailView?

I have a web app where a user signs in and begins entering items for a ToDoList . The base.html is wrapped in an is_authenticated check so users cannot see anything in the app until they have logged in. I was doing some testing with:

  • Logging in as User2
  • Adding a new ToDoListItem
  • Redirecting to the DetailView
  • In this case, the URL = http://localhost:8000/to_do_list/to_do_item/72

At this point I realized that the DetailView would allow User2 to see the details for any ToDoListItem for User1 just by entering in an existing pk into: http://localhost:8000/to_do_list/to_do_item/<int:pk> .

urls.py includes

path('to_do_item/<int:pk>', views.ToDoListItemDetail.as_view(), name='todo-item-detail'),

views.py

class ToDoListItemDetail(DetailView):
    model = ToDoListItem

todolistitem_detail.html

{% extends 'base.html' %}
{% block content %}

<a href="/">Home</a>
    <h1>DetailView for 'ToDoListItem' model</h1>
    <p>TaskTitle: '{{ object.title }}'</p>
    <p>Complete: '{{ object.is_complete }}'</p>
    <p>User: '{{ object.user}}'</p> 
{% endblock %}

What is the recommended way to prevent this from happening? I am considering the following:

  1. I could completely remove the DetailView and direct to a different URL that only returns the user's data (using something like ToDoListItem.objects.filter(user=request.user) )
  2. I could check that the name of the user logged in matches the name of the user that owns the ToDoListItem .
  3. I could override get_context_data() for the DetailView and check user ownership there (similar to no. 1, but within the DetailView)
  4. ??? (Something else better than the above I do not know about yet)

Is there a way to limit a user to only see their own data throughout an application without implementing this logic every time it is needed?

You can filter in the DetailView as well, by overriding the get_queryset method [Django-doc] :

from django.contrib.auth.mixins import LoginRequiredMixin

class ToDoListItemDetail( DetailView):

    model = ToDoListItem

    def (self, *args, **kwargs):
        return super(ToDoListItemDetail, self).get_queryset(
            *args, **kwargs
        ).filter(user=self.request.user)

Django will, behind the curtains, always call get_queryset(..) . By default this function returns the queryset of the model you specified with all objects. But you thus can filter it further down.

Django's get_object method [Django-doc] will then further filter it down with the id and/or slug , but if you already filter out the elements that do not belong to the self.request.user , then this can thus only result in an query returning no results.

It also makes sense to here add the LoginRequiredMixin [Django-doc] to your class, since in case the user did not log in, you probably want to redirect hem/her to the login screen.

There is a permission named: ¨can read¨ that allow you to handle the access. For example:

class FruitEdit(PermissionRequiredMixin,DetailView):
      permission_required = 'app.read_fruit'
      ...

I hope you can solve it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM