在上一章節(jié)中,(基于依賴項(xiàng)注入系統(tǒng)的)安全系統(tǒng)向路徑操作函數(shù)提供了一個(gè) str 類型的 token:
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
但這還不是很實(shí)用。
讓我們來(lái)使它返回當(dāng)前用戶給我們。
首先,讓我們來(lái)創(chuàng)建一個(gè)用戶 Pydantic 模型。
與使用 Pydantic 聲明請(qǐng)求體的方式相同,我們可以在其他任何地方使用它:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
讓我們來(lái)創(chuàng)建一個(gè) get_current_user 依賴項(xiàng)。
還記得依賴項(xiàng)可以有子依賴項(xiàng)嗎?
get_current_user 將具有一個(gè)我們之前所創(chuàng)建的同一個(gè) oauth2_scheme 作為依賴項(xiàng)。
與我們之前直接在路徑操作中所做的相同,我們新的依賴項(xiàng) get_current_user 將從子依賴項(xiàng) oauth2_scheme 中接收一個(gè) str 類型的 token:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
get_current_user 將使用我們創(chuàng)建的(偽)工具函數(shù),該函數(shù)接收 str 類型的令牌并返回我們的 Pydantic User 模型:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
因此現(xiàn)在我們可以在路徑操作中使用 get_current_user 作為 Depends 了:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
注意我們將 current_user 的類型聲明為 Pydantic 模型 User。
這將幫助我們?cè)诤瘮?shù)內(nèi)部使用所有的代碼補(bǔ)全和類型檢查。
Tip
你可能還記得請(qǐng)求體也是使用 Pydantic 模型來(lái)聲明的。
在這里 FastAPI 不會(huì)搞混,因?yàn)槟阏谑褂玫氖?nbsp;Depends。
Check
這種依賴系統(tǒng)的設(shè)計(jì)方式使我們可以擁有不同的依賴項(xiàng)(不同的「可依賴類型」),并且它們都返回一個(gè) User 模型。
我們并未被局限于只能有一個(gè)返回該類型數(shù)據(jù)的依賴項(xiàng)。
現(xiàn)在你可以直接在路徑操作函數(shù)中獲取當(dāng)前用戶,并使用 Depends 在依賴注入級(jí)別處理安全性機(jī)制。
你可以使用任何模型或數(shù)據(jù)來(lái)滿足安全性要求(在這個(gè)示例中,使用的是 Pydantic 模型 User)。
但是你并未被限制只能使用某些特定的數(shù)據(jù)模型,類或類型。
你想要在模型中使用 id 和 email 而不使用任何的 username?當(dāng)然可以。你可以同樣地使用這些工具。
你只想要一個(gè) str?或者僅僅一個(gè) dict?還是直接一個(gè)數(shù)據(jù)庫(kù)模型類的實(shí)例?它們的工作方式都是一樣的。
實(shí)際上你沒有用戶登錄到你的應(yīng)用程序,而是只擁有訪問令牌的機(jī)器人,程序或其他系統(tǒng)?再一次,它們的工作方式也是一樣的。
盡管去使用你的應(yīng)用程序所需要的任何模型,任何類,任何數(shù)據(jù)庫(kù)。FastAPI 通過(guò)依賴項(xiàng)注入系統(tǒng)都幫你搞定。
這個(gè)示例似乎看起來(lái)很冗長(zhǎng)??紤]到我們?cè)谕晃募谢旌狭税踩?,?shù)據(jù)模型工具函數(shù)和路徑操作等代碼。
但關(guān)鍵的是。
安全性和依賴項(xiàng)注入內(nèi)容只需要編寫一次。
你可以根據(jù)需要使其變得很復(fù)雜。而且只需要在一個(gè)地方寫一次。但仍然具備所有的靈活性。
但是,你可以有無(wú)數(shù)個(gè)使用同一安全系統(tǒng)的端點(diǎn)(路徑操作)。
所有(或所需的任何部分)的端點(diǎn),都可以利用對(duì)這些或你創(chuàng)建的其他依賴項(xiàng)進(jìn)行復(fù)用所帶來(lái)的優(yōu)勢(shì)。
所有的這無(wú)數(shù)個(gè)路徑操作甚至可以小到只需 3 行代碼:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
現(xiàn)在你可以直接在路徑操作函數(shù)中獲取當(dāng)前用戶。
我們已經(jīng)進(jìn)行到一半了。
我們只需要再為用戶/客戶端添加一個(gè)真正發(fā)送 username 和 password 的路徑操作。
這些內(nèi)容在下一章節(jié)。
更多建議: