]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:memo: Update tutorials
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 28 Dec 2018 12:03:54 +0000 (16:03 +0400)
committerSebastián Ramírez <tiangolo@gmail.com>
Fri, 28 Dec 2018 12:03:54 +0000 (16:03 +0400)
docs/src/security/tutorial003.py
docs/tutorial/extra-models.md
docs/tutorial/security/oauth2-jwt.md
docs/tutorial/security/simple-oauth2.md

index e10384c63775a62e71af0a119a3ef82cc0d12f33..d18330e9ed635c456e170752d2a6391bd6fee3c0 100644 (file)
@@ -10,6 +10,13 @@ fake_users_db = {
         "email": "johndoe@example.com",
         "hashed_password": "fakehashedsecret",
         "disabled": False,
+    },
+    "alice": {
+        "username": "alice",
+        "full_name": "Alice Wonderson",
+        "email": "alice@example.com",
+        "hashed_password": "fakehashedsecret2",
+        "disabled": True,
     }
 }
 
@@ -68,7 +75,7 @@ async def login(form_data: OAuth2PasswordRequestForm = Depends()):
     if not user_dict:
         raise HTTPException(status_code=400, detail="Incorrect username or password")
     user = UserInDB(**user_dict)
-    hashed_password = fake_hash_password(data.password)
+    hashed_password = fake_hash_password(form_data.password)
     if not hashed_password == user.hashed_password:
         raise HTTPException(status_code=400, detail="Incorrect username or password")
 
index 1cf727df8eda1160c39094f0ad1d56f0e48ed69c..ad35ffeefd35bc512b99110143533c64241a2269 100644 (file)
@@ -7,7 +7,9 @@ This is especially the case for user models, because:
 * The **database model** would probably need to have a hashed password.
 
 !!! danger
-    Never store user's plaintext passwords. Always store a secure hash that you can then verify.
+    Never store user's plaintext passwords. Always store a "secure hash" that you can then verify.
+
+    If you don't know, you will learn what a "password hash" is in the <a href="/tutorial/security/simple-oauth2/#password-hashing" target="_blank">security chapters</a>.
 
 ## Multiple models
 
@@ -17,6 +19,39 @@ Here's a general idea of how the models could look like with their password fiel
 {!./src/extra_models/tutorial001.py!}
 ```
 
+#### About `**user_dict`
+
+`UserInDB(**user_dict)` means:
+    
+Pass the keys and values of the `user_dict` directly as key-value arguments, equivalent to:
+
+```Python
+UserInDB(
+    username = user_dict["username"],
+    password = user_dict["password"],
+    email = user_dict["email"],
+    full_name = user_dict["full_name"],
+)
+```
+
+And then adding the extra `hashed_password=hashed_password`, like in:
+
+```Python
+UserInDB(**user_in.dict(), hashed_password=hashed_password)
+```
+
+...ends up being like:
+
+```Python
+UserInDB(
+    username = user_dict["username"],
+    password = user_dict["password"],
+    email = user_dict["email"],
+    full_name = user_dict["full_name"],
+    hashed_password = hashed_password,
+)
+```
+
 !!! warning
     The supporting additional functions are just to demo a possible flow of the data, but they of course are not providing any real security.
 
index 8544514a412e098acc0e13ffb626d81062e5d78a..17756468b1475ef11b93a0d4122a47fc3cb0d4ea 100644 (file)
@@ -52,7 +52,7 @@ The recommended algorithm is "Bcrypt".
 
 So, install PassLib with Bcrypt:
 
-```Python
+```bash
 pip install passlib[bcrypt]
 ```
 
index 93cf5e9959ee1e63916f46de4f57fb5234caf6dd..3d5a1a546e309912295d0a5f06fc68d66bdd1310 100644 (file)
@@ -48,7 +48,7 @@ Now let's use the utilities provided by **FastAPI** to handle this.
 
 First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`:
 
-```Python hl_lines="2 66"
+```Python hl_lines="2 73"
 {!./src/security/tutorial003.py!}
 ```
 
@@ -80,7 +80,7 @@ If there is no such user, we return an error saying "incorrect username or passw
 
 For the error, we use the exception `HTTPException` provided by Starlette directly:
 
-```Python hl_lines="4 67 68 69"
+```Python hl_lines="4 74 75 76"
 {!./src/security/tutorial003.py!}
 ```
 
@@ -94,7 +94,21 @@ You should never save plaintext passwords, so, we'll use the (fake) password has
 
 If the passwords don't match, we return the same error.
 
-```Python hl_lines="70 71 72 73"
+#### Password hashing
+
+"Hashing" means: converting some content (a password in this case) into a sequence of bytes (just a string) that look like gibberish.
+
+Whenever you pass exactly the same content (exactly the same password) you get exactly the same gibberish.
+
+But you cannot convert from the gibberish back to the password.
+
+##### What for?
+
+If your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.
+
+So, the thief won't be able to try to use that password in another system (as many users use the same password everywhere, this would be dangerous).
+
+```Python hl_lines="77 78 79 80"
 {!./src/security/tutorial003.py!}
 ```
 
@@ -129,7 +143,7 @@ For this simple example, we are going to just be completely insecure and return
 
     But for now, let's focus on the specific details we need.
 
-```Python hl_lines="75"
+```Python hl_lines="82"
 {!./src/security/tutorial003.py!}
 ```
 
@@ -145,7 +159,7 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex
 
 So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
 
-```Python hl_lines="50 51 52 53 54 55 56 59 60 61 62 79"
+```Python hl_lines="57 58 59 60 61 62 63 66 67 68 69 86"
 {!./src/security/tutorial003.py!}
 ```
 
@@ -160,6 +174,7 @@ Click the "Authorize" button.
 Use the credentials:
 
 User: `johndoe`
+
 Password: `secret`
 
 <img src="/img/tutorial/security/image04.png">
@@ -194,6 +209,24 @@ If you click the lock icon and logout, and then try the same operation again, yo
 }
 ```
 
+### Inactive user
+
+Now try with an inactive user, authenticate with:
+
+User: `alice`
+
+Password: `secret2`
+
+And try to use the operation `GET` with the path `/users/me`.
+
+You will get an "inactive user" error, like:
+
+```JSON
+{
+  "detail": "Inactive user"
+}
+```
+
 ## Recap
 
 You now have the tools to implement a complete security system based on `username` and `password` for your API.