Fast API Tutorial, Part 26: Security

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello friends and welcome back to our fast ipi tutorial in this video we're going to actually touch on security uh and deal with the first steps so first things first before i get into too much detail um i know in the last video i was going to talk about dependencies with yield um i looked over some of the examples uh it didn't really seem so that's that's kind of a a deeper topic if you will um and here i'm going to rename this as we speak let's see rename security first steps um that has a lot to do with databases and stuff like that and there's not really a good way to demonstrate how it works um without like spinning up a database and doing stuff like that and and kind of setting up an entire app and from an introductory perspective um it's not really necessarily worth it to go through that i might do it in a subsequent video but for now we're just going to stick with this so let's go ahead and get going with security first thing we're going to do we are going to declare a wrap app.get items async def read items token is going to be a string which will depend on something return token token now on what will it depend it will depend on an oauth 2 scheme so fast api has some oauth2 stuff i don't want to say built in but there is some functionality that's that's built in that works very nicely that you know we're going to take advantage of so what we're going to do we're going to set up oauth 2 scheme equals oauth 2 password bearer and we'll say token url equals token okay and now what me what that means is we need to import this from fast api dot security import this there and now this will depend on oauth2 scheme okay great what does that tell us what does that give us let's refresh the page a little bit there we go try it out execute unauthorized so what we notice i don't know if you've noticed it or not but up here in the top right we have this nice little authorize button that is now included because we're including the oauth 2 scheme okay now if we try and authorize here which by the way uh in order to use this you need to have the um the multi-part package uh installed uh it's pip install python multi-part which we already have because on a previous video we've used it but if we type user and password this should not work off not found okay and the reason is because we don't have anything to check it against right now well you know all we have is this protected route okay i'm not going to get too deep into how oauth 2 works because that's not really the point of that of this video so what we're going to do is we're going to just go straight in and kind of set up a user and do all that sort of stuff first okay so let's go ahead and create a class user that inherits from base model user name is going to be a string email is going to be a string or none which will start as none full name will be a string or none which will be none and disabled will be a boolean or none which will be none okay and now let's create a method to decode our token so we'll call it fake decode token we'll pass in the token and we'll say return user user name equals token now you know i'll use an f string um token and then fake decoded email equals foo example.com full name equals uh what do we want to call this we'll call it just foobar why is it freezing okay fubar okay so we have our decode and now what we need to do is we need to create async def get current user token is a string which depends on oauth 2 scheme user equals fake decode token of the token and return user okay now let's we're going to leave this route up here for now but let's just do app.get users me and we'll say async def get me current user which is a user equals depends on get current user and let's just return the user no current user so let's look at the flow of this for for just a second so we understand what's going on here okay so we will go back into here and refresh and we have users me try it out execute it's not going to work because we're not authorized yet now what's going to happen as we do this we're going to try and fetch the user okay we're going to call this dependency which is this right up here so here we need to take some sort of token and return a user which is just this fake decoded token thing and the token itself depends on the oauth 2 scheme okay so we're going to get the token we're going to decode it and then we're going to return the user okay now what we need to do is we need to somehow um get the username and password like we it's still not going to work because we don't have any users against which we can validate okay so let's go in here and let's create a database fake users bb equals john doe you know what i'm going to use a dictionary because it's going to be faster user name equals john doe full name equals john doe email equals john doe at example.com hashed password equals fake hashed secret disabled equals false and we'll create another one we'll say alice will be addict username equals alice full name equals alice wunderson email equals alice example.com hashed password equals fake hashed secret to and disabled equals true okay so we have that now let's create a method to hash our password first fake hash password password is a string return fake hashed password so the reason we're doing this is because you know in our database we wouldn't actually have passwords stored in plain text anyway we would have hashes so we're going to have to compare hash against hash so now let's set up another um user in db which we'll inherit from user and we're going to also add in hashed password which is a string so user ndb is a model that has all of these entries here plus it also has a hashed password now we're going to create a method get user db user name is a string if user name in db user dict equals db username return user in db user dict and i'm just writing these methods out we're going to kind of touch on these very quickly in in just a few minutes okay so now what we're going to do instead of doing this we're going to return get user fake users db and token so what fake the code token will do is we will call get user with our database which we have i'm going to minimize this which we have set up up here and all we're doing is we're saying if the username itself is in the database then the user dict is the database value so we would be passing in something like alice or john i think it's john john doe in there to get that okay and we will get the fake decode token from there now what we're going to do we're going to update get current user just a little bit so now user is still fake decode token but if not user we're going to raise an http exception status code is going to be status dot http 401 unauthorized detail equals invalid authentication credentials and headers equals www authenticate bearer and then we will return the user okay um and i think i think that's good for that now let's we got a couple more that we have to do and there's there's a whole bunch of functionality that's going on in here and we're going to see how it all ties together in just a few minutes get current active user current user is going to be a user which depends on get current user if currentuser.disabled i'm going to make this a d up here disable disabled then raise http exception status code equals 400 detail equals inactive user otherwise we will return current user okay so let's just take a look at this for a second external tools black now so we have our users me and i'm going to replace this with get current active user instead of get current user so what's going to happen here is we are going to get the current active user and return that well the current active user is going to depend on get current user well get current user takes a token so we're going to be passing in a token somehow into this method right here so we take that token we call fake decode token which in itself calls get user checks to see if that user is in the database so the token is just going to be the user's name john doe or alice we will get that user if it exists otherwise this will be none and will raise that exception if the user exists we get the user we return the user here and if the user is an active user then we will return the user otherwise we're going to be throwing exceptions up left and center now this is still not going to work because we still don't have a token right we still need to actually figure out a way to get the token itself okay so let's go ahead and do that let's let's make a route and the reason and i'll show you in just a second so now let's do app.post token async def login form data will be oauth2 password request form and we'll just say userdict equals fakeusersdb.getformdata.username and we're going to have to import this as well so let's go ahead and do that okay now first things first the reason this is called token is because when we instantiated the oauth 2 scheme uh token url was token that's literally the only reason why it's called token okay now what's going to be happening is we're going to have some sort of login functionality there's going to be some sort of form you'll notice it looks kind of like this this is the form that's going to be passed in you see token url is token okay so what we're going to do we're going to be passing in a username and a password from that we're going to get a user dict from the fake users db if you actually had a database you would have a different flow for this so let's go ahead let's say if not user dict raise http exception status code equals 400 detail equals incorrect username or password and we do it like this because you don't want to actually tell the users whether it's a username or it's a password because if they if they see that it's a valid username then um then they can just keep hitting that with different passwords and vice versa so you don't necessarily want to do that so now invalid username and password next user equals user in db user dict so we're just going to instantiate a user in db option or object from our user information that we're getting up here so we're gonna let's say we pass in john doe as the username well then we're gonna get this actual user here and we're gonna get all five fields we're gonna get username full name email hash password and disabled okay so now let's go down here hashed password equals fake password hash form data dot password so what we're doing now is we're taking the password that's being sent in here we're going to hash it using our fake method that we've created right here fake hashed and password you notice this one is fake hashed secret 2. this one is fake hashed secret so the idea is going to be that we're going to pass in the word secret or secret two it will create a fake hash and we're good now we just need to compare the two if not hashed password equals equals user dot hash password raise http exception status code equals you know what i'm just going to copy this because it's the same thing incorrect username or password we don't want to give any information otherwise we're going to return access token user.username and token type is bearer okay and that's it now we have a login method so now what we'll be able to do is we'll be able to actually get a token from this so let's go ahead and refresh so before it doesn't matter here let me let me just hide this for a second or comment it out now let's just go back here for one second uh let's try to authorize um john doe uh and what was the password here again fake hashed secret fake hashed secret authorized not found what is not found is not necessarily the user or anything like that the thing that is not found is the law is the token route because even though it's showing up here i've hidden it it's actually gone okay so that's why it's not working if we uncomment this though and we refresh refresh authorize john doe fake hashed secret if i can spell correctly let's see oh bad request what happened what happened jeff what did you do wrong did i just not type it correctly network let's try again john doe let's paste okay what's the problem here incorrect username or password oh duh duh the password is not fake hashed secret the the password is secret there we go and we have our token and if we look let's see let's see let's see uh application where is it no it's not there it's not there is it a cookie no i don't know where it is i don't know where it's actually stored right now and i'm not going to bother continuing to look but we now have a token it is a bearer token the access type is or the access token itself is john doe we can close this and now we try this out and you see we get the actual information here okay so that is a very basic um setup for password management and like you know user management and things like that you're not gonna be doing something like this um when you're building your app like you're gonna take this and have to go like a lot deeper um but it was important to see how this all goes and let's just kind of summarize again uh very quickly we've done this should not be called first steps because this is all this is a lot of stuff um so let's just take a look we've got our fake users database we've got a password hasher that we use to check the password that's being passed in we have our user model and our user in db model and what you're you are typically going to want to set this up because if you're going to be returning user information you don't want to return the hash password but you're going to want to be able to check it the hash password against the password passed in so let's go with the flow here of our users me so we're going to fetch our current active user well our current active user comes from get current user which up here takes the token now in the request that we just made our token was john doe so we call fake decode token which calls get user so we're passing in our database that is our users database from above and now we're passing in the username is john doe because that's what's actually stored as the token we fetch the user from the database using the user name and then we return the full user in db with the hashed password if we just did user then we would not get a hash password that we can check against okay now we come back we get our user we get our user now we have a user okay we have a user that's returned and we have a user that's returned and that's the information that shows up right here now the authentication what we do when we click up here let's log out we now have our our login setup so by simply adding this dependency on oauth2 scheme which we actually have right here in getcurrentuser it gives us this button the flow for this is we pass in a username and password it gets passed to the token route if we were to just do like if we did this right here try it out um john doe secret you can see we actually got our token so it's the exact same thing that's happening it's just it's happening up here reset it's happening in here and it's actually storing the token in the session somewhere i don't know exactly where so we're going to log in username and password it will hit this token endpoint first it tries to get the user dict from the users database using the username parameter here okay because that was our key the username [Music] was the key for our dictionary okay so we're going to get that user object if it doesn't exist then we're going to raise an exception if we were to type in bob and asdf authorize we get a bad request which actually turns out to be invalid or incorrect username or password now we're going to create the userndb object we're going to create a hashed password from the form data's password and then we're just going to check to see if the hash password that we have equals the user's hashed password if it doesn't again incorrect username or password otherwise we return the token to this form that is then stored in the front end okay and this flow will work for if you're you know if you're building a separate uh front end app in in view or svelte or or god forbid even in react um it will all work um this in the same way okay this is a lot this is a long video um i apologize i i wasn't intending on it being this long but i really wanted to get through it um in the next video we're going to add in one extra little little thing instead of just passing the username as the the token which is extraordinarily insecure we're going to be working with a json web token or a jot i don't know why it's called a jot it's jwt i don't know why it's called a jot i don't like it i almost always refuse to say it but that's what people call it okay i think that's enough for today have a good day everyone
Info
Channel: JVP Design
Views: 7,887
Rating: undefined out of 5
Keywords: fastapi
Id: B5AMPx9Z1OQ
Channel Id: undefined
Length: 25min 51sec (1551 seconds)
Published: Wed Jul 27 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.