Authentication II: Securing the app#
Introduction#
This is the second part of our authentication setup: we'll make sure that some actions in the app (creating posts, posting comments, etc.) are only accessible to authenticated users, while others are only accessible to a subset of authenticated users (only the authors of an article should be able to edit it, for example).
Nav#
We don't want to expose the New post
link to unauthenticated users.
In nav.html
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
LoginRequiredMixin#
Some pages should only be accessible to authenticated users, and Django provides an easy way of doing so through mixins. Mixins are components that provide common extra functionality. They can be added to class-based views on the fly.
In articles/views.py
, add the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Notice that the LoginRequiredMixin
should be at the leftmost position in the inheritance list: don't write class EditorDeleteView(DeleteView, LoginRequiredMixin)
if you want to avoid errors.
If you try creating a post from the app, you should get this error:
The cause of the problem is given in the line:
The current path, accounts/login/, didn't match any of these.
By default, the login url in Django is accounts/login
: while we changed our urls everywhere, the LoginRequiredMixin
does not know that. To fix this, we need to add this line in config/settings.py
:
1 |
|
Only allow authors to edit or delete their articles and comments#
While we're at it, let's also make sure that articles and comments can only be edited and deleted by their authors.
In templates/article_detail.html
, we hide the button for editing and deleting articles from any user who is not the article's author:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
In templates/comment_container.html
:
1 2 3 4 5 |
|
In users/views.py
, we make sure that editing or deleting actions are only taken into account if the user is the author of the article or comment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Testing signup and login#
For now, we only have one user for our app: the admin
superuser.
Let's create a new user by clicking on Sign up
in our navbar. Enter a username, an email (which doesn't have to be a real one as long as it's the right format), and a password.
When you finalise this action by clicking the button Sign up
, you'll notice that you're redirected to the homepage without being logged in. This is fine - you can sign in manually as the user you just created or you might want to implement an email verification before allowing sign ups - but, in our case, we might as well sign in the user automatically.
In users/views.py
, add the following to SignUpView
(as explained in this StackOverflow answer):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
To make sure you understand what we're doing here: Django hashes passwords when creating a new User
, but we need to make it explicit that the password
field is the password (through user.set_password(password)
) and needs to be hashed, otherwise there will be errors whenever we try to authenticate:
- Django will save the unhashed password to the database
- during login, it will take the user-submitted plaintext password and hash it
- check the hash of the user-submitted password against what it believes to be the hash of the actual password in the database
- see that the two passwords don't match (obviously)
- refuse authentication.
Now that we've resolved the issue, try creating a new user: everything should work.