Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
In "Build a Social Network with Flask", you hashed user passwords with bcrypt. Bcrypt is still very strong but, thanks to advances in GPUs, its days are numbered. A new way of securing user passwords is needed and I just happen to have one.
argon2
's documentation- Storing Passwords in a Highly Parallelized World
classmethod
docsstaticmethod
docs
You can leave the **kwargs
off of create_user
if you want. I find this to be handy way to add in flags like is_admin
or can_delete
, you just need to add them as fields on the model or in some sort of permissions system. It's a good idea to be forward-thinking in your designs!
-
0:00
[MUSIC]
-
0:04
If you did build a social network with Flask,
-
0:06
you probably remember how we hashed our users passwords with bcrypt.
-
0:11
bcrypt is still an amazing hashing Library.
-
0:13
But its main protection,
-
0:14
the fact that it can be configured to use progressively more processor time,
-
0:18
has kind of been surpassed by the creation of faster and better GPU's.
-
0:22
This advance in hardware means that our software has been given a best by date.
-
0:26
Thankfully some for development doesn't just sit on its laurels and new
-
0:29
hashing libraries and techniques have been created that stress processors and memory.
-
0:35
No matter how much processor power you have,
-
0:36
eventually you will run out of memory.
-
0:39
Let's go see about building users with argon2 hashed passwords.
-
0:43
Before I can use the argon2 library to hash passwords.
-
0:47
I have to install it.
-
0:49
So for python, I'm just gonna pip install aargon2-cffi.
-
0:53
There are argon2 packages for lots of other languages.
-
0:57
And whenever you're installing this, you might find that you are missing ffi, so
-
1:02
you'll just need to lookup how to install that for
-
1:05
whatever your operating system is.
-
1:06
I've put a link to the argon2 docs in the teacher's notes, so
-
1:09
be sure to check there if there's something you wanna know more about.
-
1:12
I've also included a blog post from a friend of mine named Hinnick,
-
1:15
about why to use something like argon2, instead of bcrypt or whatever.
-
1:21
Okay, so I've got argon2 installed.
-
1:23
I think it's time to make a user model.
-
1:26
Let's make a new model up here.
-
1:30
And I'm gonna make it above these others, so that I can do foreign keys to them.
-
1:35
You know what, actually before, let's do a couple of other things here real quick.
-
1:42
So we need to do from argon2 import PasswordHasher.
-
1:50
And then I have these config things here,
-
1:52
I think I wanna move those into a new file.
-
1:54
So let's make a new file.
-
1:56
And we're gonna call this config.py.
-
2:01
And we'll take these things and cut them.
-
2:07
And then we will paste them into here.
-
2:14
And then let's get rid of that line, and let's just say import config.
-
2:21
And then down here,
-
2:24
I'll add this as config., config.
-
2:29
and config.
-
2:31
Cool.
-
2:32
So, I can save that.
-
2:35
And I wanna add one more item in here.
-
2:37
I want to add a secret_key.
-
2:40
And then you're just going to add a bunch of random characters to your secret key.
-
2:50
Just make it all fancy.
-
2:53
And then from here of course I want to do import config.
-
2:56
Now you might consider moving the database out to there as well just for kind of
-
3:03
putting everything together, but I'm not gonna worry about that for right now.
-
3:07
Okay, so let's add a HASHER in here which will be the PasswordHasher.
-
3:13
Okay, so let's make this user model.
-
3:15
All right, so users should have a username.
-
3:18
And that'll be a char field and I want that to be unique because I don't wanna
-
3:23
have more than one user with the same username, of course.
-
3:26
And then I'm gonna do a char field for the email address.
-
3:29
And I'm also gonna make that unique because again
-
3:32
I don't want more than one user to have the same stuff.
-
3:36
And then let's do password is equal to a CharField.
-
3:39
And I'm not gonna set any requirements on that.
-
3:42
So class meta database = database.
-
3:47
All right and then I want to provide a method for
-
3:50
creating a user and this should be
-
3:55
a class method because I need to work on the class and not on an instance.
-
4:01
So we're gonna accept the class.
-
4:03
And we're gonna take the username.
-
4:05
And we're gonna take the email.
-
4:06
And we're gonna take the password.
-
4:07
And we're gonna take any other cards that happen to come in.
-
4:10
Right now we don't care about them but who knows,
-
4:13
maybe in the future we want to allow their arguments.
-
4:16
All right. So first of all,
-
4:17
let's lowercase this email.
-
4:20
And then let's do cls.select
-
4:24
.where, we need two things here.
-
4:29
So, csl.email is equal to e-mail that was passed in.
-
4:34
Or cls.username is like,
-
4:37
case insensitive, is like username.
-
4:43
And then do a .get on that.
-
4:45
And then, if we get a cls.DoesNotExist error.
-
4:52
Then, that's good.
-
4:54
That means that the user doesn't exist.
-
4:58
So, we'll do An email=email.
-
5:05
And then I’m gonna do user.password = user.set password.
-
5:11
And provide the password.
-
5:13
User.save and return user.
-
5:17
Else, let's raise an exception.
-
5:19
And let's say user with that email or username already exists.
-
5:29
All right, cool.
-
5:30
So now, I need to produce this set password method.
-
5:37
So this is gonna be a static method.
-
5:38
Because again I don't want it to operate on an instance.
-
5:41
But I don't even want it to operate on the class.
-
5:43
I want it to just be this method that happens to belong to the user class.
-
5:46
But it doesn't care anything at all about the class,
-
5:48
which is why I say static method.
-
5:50
So we're gonna set the password, and we're gonna put in the password.
-
5:55
And we're gonna return HASHER.hash(password).
-
6:02
Cool, and then let's make a verify_password.
-
6:09
And this is actually going to take an instance.
-
6:11
This is just a normal everyday method nothing.
-
6:14
Nothing special about this one.
-
6:15
And we're gonna return HASHER.verify,
-
6:20
that self.password matches password.
-
6:24
And so argon2 is kind of cool because it actually throws an exception if
-
6:28
the passwords don't match.
-
6:30
So if this step was to fail it would throw an exception.
-
6:33
Because argon2 doesn't have any concept of not matching or an invalid password.
-
6:39
It just know these two things don't match.
-
6:42
Ideally you get the idea of how that works.
-
6:46
There's nothing really different about this.
-
6:49
One thing I will point out is that we don't actually need this.
-
6:52
In workspaces because we're using SQLite.
-
6:54
SQLite is really horrible with case sensitive searching.
-
6:58
So SQLite will work fine without that.
-
7:01
You do wanna have this for all the other databases, MySQL, Postres,
-
7:05
things like that.
-
7:06
I think we're good there and I'm going to go and make a user resource off camera.
-
7:13
I want you to try and make one on your own.
-
7:15
All it needs to have is a user list with a post that will create a new user.
-
7:19
That's all you have to make.
-
7:20
Go ahead and register it with the app and everything.
-
7:22
We'll check that out in the next video.
-
7:25
One thing that's really smart to do and Django does it Is if you want an example
-
7:28
is to create a way to upgrade password hashing.
-
7:31
You don't want to store the actual passwords but
-
7:34
when you use a new hasher to create an upgrade path,
-
7:36
that will change your users old hash to the new one the next time they will login.
-
7:40
You'll have a more secure application and
-
7:42
they'll appreciate not getting any we've been hacked e-mails.
You need to sign up for Treehouse in order to download course files.
Sign up