diff --git a/docs/tutorial/security/get-current-user.md b/docs/tutorial/security/get-current-user.md new file mode 100644 index 000000000..88099fb27 --- /dev/null +++ b/docs/tutorial/security/get-current-user.md @@ -0,0 +1,120 @@ +In the previous chapter the security system (which is based on the dependency injection system) was giving the path operation function a `token` as a `str`: + +```Python hl_lines="10" +{!./src/security/tutorial001.py!} +``` + +But that is still not that useful. + +Let's make it give us the current user. + +## Create a user model + +First, let's create a Pydantic user model. + +The same way we use Pydantic to declare bodies, we can use it anywhere else: + +```Python hl_lines="5 12 13 14 15 16" +{!./src/security/tutorial002.py!} +``` + +## Create a `get_current_user` dependency + +Let's create a dependency `get_current_user`. + +Remember that dependencies can have sub-dependencies? + +And remember that `Security` is based on `Depends`? + +So, we can have sub-dependencies using `Security` too. + +`get_current_user` will have a `Security` dependency with the same `oauth2_scheme` we created before. + +The same as we were doing before in the path operation direclty, our new dependency will receive a `token` as a `str` from the `Security` dependency: + +```Python hl_lines="25" +{!./src/security/tutorial002.py!} +``` + +## Get the user + +`get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model: + +```Python hl_lines="19 20 21 22 26 27" +{!./src/security/tutorial002.py!} +``` + +## Inject the current user + +So now we can use the same `Depends` with our `get_current_user` in the path operation: + +```Python hl_lines="31" +{!./src/security/tutorial002.py!} +``` + +!!! info + Here you could actually use `Security` instead of depends too. + + But it is not required. + + The key point where you should use `Security` is when passing an instance of `OAuth2PasswordBearer`. + + Because **FastAPI** will use the fact that you are using `Security` and that you are passing an instance of that class `OAuth2PasswordBearer` (that inherits from `SecurityBase`) to create all the security definitions in OpenAPI. + +Notice that we declare the type of `current_user` as the Pydantic model `User`. + +This will help us inside of the function with all the completion and type checks. + +!!! tip + You might remember that request bodies are also declared with Pydantic models. + + Here **FastAPI** won't get confused because you are using `Depends` or `Security`. + +!!! check + The way this dependency system is designed allows us to have different dependencies (different "dependables") that all return a `User` model. + + We are not restricted to having only one dependency that can return that type of data. + + +## Other models + +You can now get the current user directly in the path operation functions and deal with the security mechanisms at the **Dependency Injection** level, using `Security`. + +And you can use any model or data for the security requirements (in this case, a Pydantic model `User`). + +But you are not restricted to using some specific data model, class or type. + +Do you want to have an `id` and `email` and not have any `username` in your model? Sure. You can use these same tools. + +Do you want to just have a `str`? Or just a `dict`? Or a database class model instance directly? It all works the same way. + + +## Code size + +This example might seem verbose. Have in mind that we are mixing security, data models utility functions and path operations in the same file. + +But here's the key point. + +The security and dependency injection stuff is written once. + +And you can make it as complex as you want. And still, have it written only once, in a single place. + +But you can have thousands of endpoints (path operations) using the same security system. + +And all of them (or any portion of them that you want) can take the advantage of re-using these dependencies or any other dependencies you create. + +And all these thousands of path operations can be as small as 3 lines: + +```Python hl_lines="30 31 32" +{!./src/security/tutorial002.py!} +``` + +## Recap + +You can now get the current user directly in your path operation function. + +We are already halfway there. + +We just need to add a path operation for the user / client to actually send the `username` and `password`. + +That comes next. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 6dc5e9926..8f9bab9e0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -48,6 +48,7 @@ nav: - Security: - Security Intro: 'tutorial/security/intro.md' - First Steps: 'tutorial/security/first-steps.md' + - Get Current User: 'tutorial/security/get-current-user.md' - Simple OAuth2 with Password and Bearer: 'tutorial/security/simple-oauth2.md' - OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md' - SQL (Relational) Databases: 'tutorial/sql-databases.md'