Browse Source

Add docs for HTTP Basic Auth and tests (#177)

pull/183/head
Sebastián Ramírez 6 years ago
committed by GitHub
parent
commit
c705685394
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. BIN
      docs/img/tutorial/security/image12.png
  2. 11
      docs/src/security/tutorial006.py
  3. 22
      docs/src/security/tutorial007.py
  4. 40
      docs/tutorial/security/http-basic-auth.md
  5. 1
      mkdocs.yml
  6. 12
      tests/test_tutorial/test_security/test_tutorial006.py

BIN
docs/img/tutorial/security/image12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

11
docs/src/security/tutorial006.py

@ -0,0 +1,11 @@
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
return {"username": credentials.username, "password": credentials.password}

22
docs/src/security/tutorial007.py

@ -0,0 +1,22 @@
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.status import HTTP_401_UNAUTHORIZED
app = FastAPI()
security = HTTPBasic()
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
if credentials.username != "foo" or credentials.password != "password":
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: str = Depends(get_current_username)):
return {"username": username}

40
docs/tutorial/security/http-basic-auth.md

@ -0,0 +1,40 @@
For the simplest cases, you can use HTTP Basic Auth.
In HTTP Basic Auth, the application expects a header that contains a username and a password.
If it doesn't receive it, it returns an HTTP 401 "Unauthorized" error.
And returns a header `WWW-Authenticate` with a value of `Basic`, and an optional `realm` parameter.
That tells the browser to show the integrated prompt for a username and password.
Then, when you type that username and password, the browser sends them in the header automatically.
## Simple HTTP Basic Auth
* Import `HTTPBAsic` and `HTTPBasicCredentials`.
* Create a "`security` scheme" using `HTTPBAsic`.
* Use that `security` with a dependency in your *path operation*.
* It returns an object of type `HTTPBasicCredentials`:
* It contains the `username` and `password` sent.
```Python hl_lines="2 6 10"
{!./src/security/tutorial006.py!}
```
When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
<img src="/img/tutorial/security/image12.png">
## Check the username
Here's a more complete example.
Use a dependency to check if the username and password are correct.
If the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
```Python hl_lines="10 11 12 13 14 15 16 17 21"
{!./src/security/tutorial007.py!}
```

1
mkdocs.yml

@ -58,6 +58,7 @@ nav:
- 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'
- OAuth2 scopes: 'tutorial/security/oauth2-scopes.md'
- HTTP Basic Auth: 'tutorial/security/http-basic-auth.md'
- Middleware: 'tutorial/middleware.md'
- CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md'
- Using the Request Directly: 'tutorial/using-request-directly.md'

12
tests/test_security_http_basic.py → tests/test_tutorial/test_security/test_tutorial006.py

@ -1,19 +1,9 @@
from base64 import b64encode
from fastapi import FastAPI, Security
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from requests.auth import HTTPBasicAuth
from starlette.testclient import TestClient
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: HTTPBasicCredentials = Security(security)):
return {"username": credentials.username, "password": credentials.password}
from security.tutorial006 import app
client = TestClient(app)
Loading…
Cancel
Save