How to prevent user from changing url <pk> to see other submit data Django

I am new to the world of web development, Django, and applications that require url protection from users who change foo / bar / pk in order to access other user data.

Is there a way to prevent this? Or is there a built-in way to prevent this in Django?

etc .: foo/bar/22

can be changed to foo/bar/14

and provide data of past users.

I have read the answers to several questions on this topic and have no luck with an answer that can explain this clearly and consistently and the approach to prevent it. I don’t know a ton about this, so I don’t know how to frame this question in order to research it properly. Please explain it to me like I'm 5.

+3


source to share


6 answers


There are several ways to achieve this:

Once you have the concept of login, just limit the url:

/foo/bar/

      

and in code user=request.user

and display data only for the registered user.

Another way:



/foo/bar/{{request.user.id}}/

      

and in the view:

def myview(request, id):
    if id != request.user.id:
        HttpResponseForbidden('You cannot view what is not yours') #Or however you want to handle this

      

You can even write middleware that redirects the user to your page /foo/bar/userid

- or to the login page if you're not signed in.

+5


source


I would recommend using django-guardian if you want to control access to each object. This is how it will look after setting the options and installing (this is from the django-guardian docs ):

>>> from django.contrib.auth.models import User
>>> boss = User.objects.create(username='Big Boss')
>>> joe = User.objects.create(username='joe')
>>> task = Task.objects.create(summary='Some job', content='', reported_by=boss)
>>> joe.has_perm('view_task', task)
False

      

If you'd rather not use an external library, there are also ways to do this in Django views .



This is how it might look:

from django.http import HttpResponseForbidden
from .models import Bar

def view_bar(request, pk):
    bar = Bar.objects.get(pk=pk)
    if not bar.user == request.user:
        return HttpResponseForbidden("You can't view this Bar.")
    # The rest of the view goes here...

      

+3


source


Just make sure the object retrieved by the primary key belongs to the requesting user. In view it will be

if some_object.user == request.user: ...

This requires the model representing the object to have a reference to the user model.

+3


source


You will want to look into user authentication and authorization, which both come with the Django Auth package . There's a big difference between the two.

Authentication ensures that someone is who they are. Think, come in. You get someone to kiss their username and password to prove they are the owner of the account.

Authorization ensures that someone can access what they seek to access. Thus, a normal user, for example, cannot simply switch PK.

The authorization is well documented in the link above. I would start there and skip some code examples. Hope this answers your question. If not, hopefully he will provide you with enough information to come back and ask a more specific question.

+2


source


In django, the user is currently logging into your views as a property user

of the request object.

The idea is to filter your models by the logged in user first, and then if there are any results, they will only show those results.

If a user tries to access an object that does not belong to them, do not show the object.

One way to take care of all of this is to use a shortcut function get_object_or_404

that will throw a 404 error if an object that matches the given parameters is not found.

Using this, we can just pass the primary key and the currently logged in user to this method if it returns an object, i.e. the primary key belongs to that user, otherwise it will return 404 as if the page didn't exist.

It's pretty easy to hook it up to your view:

from django.shortcuts import get_object_or_404, render

from .models import YourModel

def some_view(request, pk=None):
    obj = get_object_or_404(YourModel, pk=pk, user=request.user)
    return render(request, 'details.html', {'object': obj})

      

Now if a user tries to access a link from pk that doesn't belong to them, a 404 is added.

+2


source


In my project, for multiple models / tables, the user should only see the data they entered, not the data entered by other users. There is a user column for these models / tables.

In a list view, which is easy enough to implement, just filter out the queryset passed to the list view for model.user = loggged_id.user.

But for detail / update / delete views, seeing the PK in the url would suggest that the user can edit the PK in the url and access another custom string / data.

I am using Django built from class.

Views with PK in the URL already have LoginRequiredMixin, but this does not prevent the user from changing the PK in the URL.

My solution: "Logged into User Own This Row Mixin" (DoesLoggedInUserOwnThisRowMixin) - override the get_object method and test there.

from django.core.exceptions import PermissionDenied

class DoesLoggedInUserOwnThisRowMixin(object):

    def get_object(self):
        '''only allow owner (or superuser) to access the table row'''
        obj = super(DoesLoggedInUserOwnThisRowMixin, self).get_object()
        if self.request.user.is_superuser:
            pass
        elif obj.iUser != self.request.user:
            raise PermissionDenied(
                "Permission Denied -- that not your record!")
        return obj

      

Voila!

Just put a mixin on the view class definition line after LoginRequiredMixin and with a 403.html template that outputs the message, you're good to go.

0


source







All Articles