Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Well done!
You have completed Flask REST API!
You have completed Flask REST API!
Preview
Users are just the first step. Once you know who someone is, you need to be able to let them in. HTTP Basic Auth is a great solution for this for APIs because it's accessible through HTTP headers and browsers.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
One of the simplest ways to
handle authentication on the web
0:00
is known as HTTP basic auth.
0:03
It's a whole lot like being presented
with a login form on a site or
0:05
on your OS but
it comes out in your browser.
0:09
The neat thing about basic auth though
is that you can send your credentials,
0:12
your username and password to it through
HTTP headers which means that our users
0:16
can send their credentials when they
request a protected section of our site.
0:20
Miguel Grinberg created a great
package for doing http based
0:24
auth in a Flask project that handles a lot
of the needs I have on this project.
0:28
A link to the docs for
that in the teacher's notes.
0:33
But, as usual, before I can use it,
I need to install it.
0:35
So I'll do pip install flask-httpauth.
0:41
And there we go.
0:47
It's all installed.
0:48
And so now we need to use this.
0:51
Now, one thing I wanna point out.
0:52
I'm using version 3.1.1.
0:53
Make sure that you're using 3.1.1 or
higher.
0:57
Some earlier versions didn't
have all of the little bits and
1:00
pieces that we need, so
you get to use 3.11 or
1:03
higher to have all the stuff that
I'm gonna use in this course.
1:07
Okay, so with that installed we can
start building the actual auth part.
1:12
Now I'm wanna do this in a new file which
I'm gonna call auth.py because I know that
1:16
I'm gonna want to use the authentication
requirements in more than one place.
1:22
Since, we have more than one resource.
1:27
And imports are a little easier if
the stuff I'm importing isn't in app.py or
1:29
something like that.
1:34
Also, I know I'm going to make
more than just one kind of auth.
1:35
Thanks to the magic of writing
a script ahead of time.
1:38
So having all of these
things in one place,
1:42
separated from everything else,
makes the whole thing so much nicer.
1:44
So in auth.py I'm gonna
create a basic HTTP, a basic,
1:48
HTTP basic, yep auth implementation.
1:53
So here we go from flask import g,
we're gonna need the flask g object,
1:56
the global object,
to pass around who the user is.
2:01
From flask.ext.httpauth
import HTTPBasicAuth.
2:05
And the cool thing about BasicAuth
is a thing your browser can just do.
2:11
You don't have to do anything special.
2:13
So remember earlier, I was talking
about how we're looking in form, so
2:16
that you can just send forms to your API.
2:19
You can send HTTPBasicAuth
to your API as well,
2:21
which means you don't really need
JavaScript for any of these.
2:24
All right so the one we'll call
basic_auth as HTTPBasicAuth(), and
2:29
then we'll make a new function here.
2:34
And so @basic_auth.verify_password.
2:37
verify_password.
2:44
So this function will take a user and
a password and
2:45
make sure that user has that password.
2:50
So we're gonna accept email or
2:52
username because I don't really
care which one they give to me.
2:54
One is as good as the other.
2:58
And so then we're gonna try and
do user = models.User.get.
3:00
And it either needs to be
models.User.email.==email_or_username,
3:07
or
models.User.username==email_or_username.
3:15
All right, cool.
3:23
So the nice thing about this is, again
they can use either one of these things.
3:23
So now if not
user.verify_password(password).
3:28
So we've gotten the user based on
the username or the email address.
3:34
Now make sure that password is true,
3:38
otherwise we're gonna return
False if it's not that user.
3:40
except models.User.DoesNotExist.
3:44
Then in this case we
also wanna return False.
3:49
Else, assuming everything's good, right.
3:53
So we've gotten a user and
their password is correct.
3:55
The user does actually exist.
3:59
Then we're gonna set g.user = user and
we're gonna return true.
4:01
I'll walk you through this one more time.
4:07
We try to get a user that has either the
email or the username that was supplied.
4:09
If we don't get a user,
so we get this exception,
4:14
then we're gonna return false right away.
4:17
If we do get a user then we're
gonna verify their password.
4:19
If that password doesn't verify,
then we're gonna return false.
4:22
If the password does verify,
we jump all the way out here to this else.
4:25
We set the global user to
be the user that we got and
4:29
we return True because they are verified,
or the password is verified.
4:33
So then that's all that stuff.
4:40
All right, so it's time for me to go mark
some stuff as requiring authentication.
4:41
I know,
again through the magic of television,
4:46
that I'm gonna want a variable named
auth as the variable that I use.
4:48
So I'm just gonna do auth = basic_auth,
for right now.
4:53
Just so that I always have this thing
called auth that's hanging around.
4:57
All right, so let's go secure some
of the review and course methods.
5:00
Let's start in courses.py and up here
I'm gonna do from auth import auth.
5:07
Not the best import ever,
but you know what?
5:15
It works, it works.
5:18
All right, so now I need to protect
the things that I want protected.
5:20
I think.
5:24
Let's look at these one on one.
5:25
I think getting a list of
courses should be open.
5:26
But I think that posting a new
course should be protected.
5:31
So @auth.login_required.
5:36
Okay, so I'm gonna put that there.
5:40
All right, and
then I think that getting a single
5:42
course should be fine but
we should protect the put and
5:47
we should probably protect
the delete as well.
5:53
And I would even go so far as to say
like users can't delete these things,
6:00
average everyday users we want this
to be restricted just to admins or
6:05
somebody with special privileges.
6:10
Yeah, this week probably we wanna
work on something else, but for
6:12
right now that's fine.
6:15
So let's go repeat some
of that here in reviews.
6:17
So from auth import auth.
6:20
And then, on reviews.
6:24
Again I think getting a list of reviews,
should be fine.
6:26
Posting in a review should be locked down.
6:29
Getting an individual review should
be open but updating a view.
6:34
And deleting a review
should both be protected.
6:41
And, I actually think those should be
protected in a new and different way.
6:49
I think those should be protected to
the point of not being able to edit or
6:55
delete ones that you don't own.
7:00
So the first thing we have
to do is we have to import g
7:02
because we have to be able to
find out who the user is, right?
7:06
So then, let's come down here and
let's change our review-post.
7:11
So, we're going to do the **args, but
then we're also gonna do a new one.
7:18
We're gonna do created_by.
7:26
That's what we called it on the model,
right.
7:27
Let's double check.
7:29
created_by.
7:30
And we're gonna make that equal to g.user.
7:33
So that way we know who created it.
7:37
Okay.
7:39
Then, we're gonna come
down here to the put.
7:40
And we need to do the review or
404 but I think we have to change that.
7:43
I don't think we can do just review or
404.
7:48
I think now we need to do
something a bit more complex.
7:50
So let's do review = models.review.select,
7:54
.where Models.review.
7:59
Created by is equal to g.user.
8:03
And models.review.id is equal
to the id that comes in, and
8:06
then we'll close that where,
and then we'll do a .get.
8:09
And then we need an except,
models.Review.DoesNotExist.
8:14
return make_response.
8:22
json.dumps.
8:23
Error that review does not exist or
is not editable.
8:27
So that's cool.
8:35
There's that.
8:36
And then we'll send that back with
a 403 because that is a bad response.
8:38
Then out here, we can get rid of that, and
8:44
the rest of this is just
like it was before.
8:50
Yep.
None of that has to change,
8:55
but that means we need to
import make_response, and
8:56
we also need to import json.
9:00
All right.
9:02
So now, let's go do the same thing.
9:04
In fact we can just copy this.
9:08
Do the same thing right here in delete.
9:11
So instead of that review there,
we're gonna paste in
9:13
this thing where we get the review
that belongs to a particular user.
9:18
So this way, you have to own the review
to be able to edit or delete the review.
9:23
I think that helps a lot.
9:28
And then like I said on courses.
9:31
I don't think we would lock
down the stuff beyond,
9:33
they're requiring a user unless again we
wanted to make it to where it required
9:36
a user with particular permissions.
9:41
Now, this does have the downside
of sending usernames and
9:44
passwords in plain text
across the Internet.
9:47
This is when I remind you that you should
always have an SSL certificate for
9:49
anything that uses a login.
9:54
And especially if there is money or
personal details involved.
9:56
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up