Building Data-Driven Web Apps with Flask and SQLAlchemy Transcripts
Chapter: User input and HTML forms
Lecture: Creating the user
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
Well we've almost finished the registration process
0:02
and our interaction with forms are working really well.
0:04
But, let's go work on this other bit here.
0:07
Let's actually go and create the user.
0:09
So let's do this.
0:10
Let's say the user's going to be our user_service
0:13
remember we're doing lots of stuff with the database
0:15
and users, so we created our user_service over here.
0:19
So we can just import that.
0:22
We're going to add a function, not get_user_count
0:24
but create_user.
0:26
We're going to have a bunch more things as well
0:27
and we can just pass the values: name, email and password.
0:33
Now, this doesn't exist yet
0:34
but, you know what, we can have PyCharm write it for us
0:37
and this can be a string and a string and a string.
0:44
And let's actually tell it here
0:46
that it's going to return not a user
0:48
but an optional user. Why optional?
0:52
Well you'll see in a second.
0:53
But we definitely want to return
0:54
some kind of user here.
0:56
That's just the end of the line, okay.
0:59
Cool, cool, okay.
1:00
So what we need to do here is
1:01
we should also do some validation
1:03
on name and email and so on
1:04
but we're doing that at the top as well.
1:06
Let's just trust it for the moment
1:08
but in a real site we would add that.
1:09
So how do we do this?
1:10
We're going to create a user, like so.
1:15
And we're going to set some values.
1:17
Now, be super, super careful here.
1:20
Do you do this? Maybe? No.
1:24
Bad, bad, don't do that.
1:25
You never, ever, ever want to store
1:28
your password directly in the database.
1:31
It's such a bad idea to store the password in plain text.
1:34
If for some reason you have a SQL injection attack
1:37
or your database gets lost, or whatever
1:40
all sorts of bad things are going to happen.
1:42
So we never, ever, ever want to do this.
1:43
So instead, let me show you how we're going to
1:45
handle passwords in our app.
1:47
So come over here, and let's check out
1:49
this thing called passlib.
1:50
This is one of my favorite of all time modules for Python
1:53
because it just takes this tricky problem
1:56
and makes it super, super nice.
1:58
So the way that it works is this thing will go
2:01
you can import it and it will go and hash up
2:04
some kind of thing like, I don't know, a password.
2:07
And then it will verify it.
2:09
Now, of course you could use MD5 or SHA512 or whatever
2:14
but this does a lot more.
2:15
It also creates random salt, that is like
2:17
words that are mixed in with the password.
2:20
And it folds it many, many times.
2:23
Now what I mean by that, instead of just
2:24
taking the value and hashing it
2:25
it takes that result and hashes it again
2:27
and then it hashes it again and hashes it again
2:29
like 150,000 times.
2:32
So this is a much, much harder to break password
2:35
if for some reason someone were able to access your database
2:38
and get a hold of the emails and the passwords.
2:42
So this is pretty easy for us to use.
2:44
We have to add passlib to our requirements
2:51
down here like so.
2:54
Make sure those get installed.
2:56
So this is all good
2:57
and then up here at the top
2:59
we need to go and import some stuff.
3:00
But we're going to go over here
3:01
and we're going to say
3:07
from passlib.handlers.sha2_crypt import sha512_crypt as crypto
3:08
We're going to import SHA512
3:12
and let's do this as crypto.
3:16
That way when we use it below
3:17
if for some reason we decide we want
3:18
to change our handler or something
3:20
we can do that pretty easily.
3:22
So now I'm just going to drop two functions down here.
3:24
One is to do the hashing and one is to do the verification.
3:27
Okay?
3:28
So we have hash.txt, which takes plain text and encrypts it
3:32
and we're setting the rounds
3:33
to be something kind of random but really high.
3:35
171,204 iterations, that's going to make it
3:39
extremely computationally challenging to break.
3:43
And then we want to go and verify it.
3:45
You can't directly compare these
3:47
because each encryption result results in using random salt
3:51
but once one of these strings exists
3:53
it knows how to verify it.
3:54
So what we're going to do here
3:55
is just a super simple hash.txt
3:57
and give it the password.
3:59
There we go. That's much better.
4:01
And now we're going to need one of these sessions, like so.
4:04
I'm going to say session.commit when we're done
4:07
and we're going to return the user.
4:09
All right, and then before we actually call commit
4:12
we need to do session.add, remember that?
4:14
And that'll add it here.
4:15
Now, this all looks pretty good.
4:17
There's one other issue, we may have a problem here.
4:20
So let's just write one more function
4:21
and you'll see why.
4:23
Def find_user_by_email.
4:32
And it's going to do something super simple
4:33
but it's going to come down here and say
4:36
return session of query.
4:38
And so what we're going to do is find
4:40
and see if somebody's already registered
4:42
with this email address
4:43
because that would be bad to re-register them, right?
4:53
All right, so that's going to just give us the one user back
4:56
and let's say if find_user_by_email
5:01
this email address, return None.
5:05
So we don't want to create the user
5:07
otherwise this user has not registered with us yet
5:09
we're going to create their account
5:11
we're going to set their values, hash their password
5:14
put them in the database, commit it and return it.
5:17
Phew, all right.
5:18
So that seems like a lot, but I think we're good.
5:20
Let's do a quick test, if not user
5:21
that meant we couldn't create it.
5:23
Let's do something like this. Here we go.
5:28
So if for some reason the thing already exists
5:31
we're going to bail, otherwise we'll redirect.
5:33
Let's go and actually do a quick query, look in our database
5:35
and see if this user already exists, or not.
5:39
It shouldn't exist. Go here.
5:44
Say select star from users.
5:47
What your email is, michael@talkpython.fm.
5:53
We run that, look, zero rows.
5:54
All right, now, now let's go try to run this, here.
5:59
Make sure everything's working, good, good.
6:01
Now let's go try to register again.
6:03
So I'm going to be Michael.
6:09
Right, here we go.
6:10
It should go through, actually let's not
6:12
put the password yet. Some fields are missing.
6:15
Let's go and try to register.
6:17
Boom, it went through. It didn't crash.
6:20
All of these are really good signs.
6:22
Let's go to the database and ask that question again.
6:25
Look at that, user 85 is now registered.
6:28
Michael, michael@talkpython.
6:29
Here's that crazy password.
6:32
Like, that's really not very much
6:34
at all like what I typed, right?
6:36
That's not the letter a.
6:37
Down here we have our logins, our created_date
6:40
we didn't set the profile image, that's all fine.
6:42
Let's do one more test.
6:43
Let's go back and try to register again.
6:45
I'm Jeff. And my email address is that.
6:50
Let's try again. A user with that email already exists.
6:53
Okay, great, I think our forms
6:55
and our user interaction is pretty good.
6:57
At least on the registration level.