Two different questions. Authentication asks who you are. Authorization asks what you may do. They are separate, and the second is the one people forget.
@login_required on an edit view means any signed-in person can edit any post, by changing the number in the URL. That is not a hypothetical: it is one of the most common real vulnerabilities in hobby projects, and it takes about four seconds to exploit.
Restricting to the owner
Check after
# checked afterwards, and
# easy to forget somewhere
post = get_object_or_404(
Post, pk=pk
)
if post.author != request.user:
raise PermissionDenied
→
Filter the query
# impossible to fetch
# someone else's at all
post = get_object_or_404(
Post,
pk=pk,
author=request.user,
)
Compare → Both work. The right one is safer because there is no separate step to leave out, and it fails as a 404 rather than confirming that the post exists but belongs to someone else.
✦ Hiding the button is not access control
Wrapping an edit link in {% if post.author == user %} is good interface design and no security at all. The URL is still there, and anyone can type it. Every check that matters happens in the view. The template only decides what is shown.
◈ Graded Challenge
Write can(action, user, post) deciding what a person may do. user is a dictionary with keys name and is_staff. post is a dictionary with keys author and published. The rules: anyone, including someone signed out where user is None, may "view" a published post. Only the author or staff may view an unpublished one. Only the author or staff may "edit". Only the author or staff may "delete". A user who is None may never edit or delete anything. Return True or False.
Name it exactly: can(action, user, post)
Python4 visible + 6 hidden
loading editor…
Mark this lesson complete
Signed in, your progress follows you to every device.