一、介紹
OAuth2 .0模式有四種分別是:
- 授權碼授權模式(Authorization Code Grant)
- 隱式授權模式(Implicit Grant)
- 密碼授權模式(Resource Owner Password Credential Grant)
- 客戶端憑證授權模式(Client Credentials Grant)
這里探討的是第三種模式密碼授權模式(Resource Owner Password Credential Grant),這種模式的流程:
FastAPI中使用OAuth2來看一下它是如何使用工作的,然后來理解發生了什么。
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}
訪問 http://127.0.0.1:8000/docs#/
在路徑操作的右上角有一個可以點擊的鎖,如果你點擊它,你會得到一個由username和password(以及其它的可選字段)的認證的表單。
現在理解一下這個流程:
- 在前端輸入用戶的username和password
- 前台將用username和password發送給后台一個特殊API的URL(通過tokenUrl="token"聲明的)
- 這個特殊的API檢查username和password,然后返回一個“token”,在下次請求時將會通過這個token進行用戶驗證,正常的是這個token是有過期時間的
- 這個token前端會臨時存儲在某個地方
- 然后每次請求時會攜帶一個Authorization的請求頭
- 后台會檢查Authorization請求頭中是否有token值,如果沒有,直接返回401狀態碼以及UNAUTHORIZED錯誤信息
FastAPI在不同的抽象級別提供了幾個工具,用來實現這些安全特性。
二、OAuth2PasswordBearer
1、參數說明
當我們通過OAuth2PasswordBearer類來創建一個實例,並且通過tokenUrl參數傳遞一個URL,客戶端將會將username和password傳遞到這個URL對應的路徑操作函數中,然后得到一個token。
... oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") ...
此處的tokenUrl="token"是相對路徑,相當於tokenUrl="./token"。
oauth2_schemes實例變量是可調用的,這就意味着它可以作為依賴項。所以在路徑操作函數中:
... @app.get("/items/") async def read_items(token: str = Depends(oauth2_scheme)): return {"token": token} ...
這個依賴項提供一個str用來標記路徑操作函數的token參數。FastAPI知道它可以使用這個依賴在OpenAPI中來定義一個“安全模式”(以及自動交互的API文檔)。
2、獲取當前用戶
上述基於安全系統向路徑操作函數提供了一個str類型的token,但這並不是很實用,實際上可以使它返回當前的用戶信息。
- 創建用戶模型
from typing import Optional from pydantic import BaseModel class User(BaseModel): username: str email: Optional[str] = None full_name: Optional[str] = None disabled: Optional[bool] = None
- 創建get_current_user依賴項
此時可以將oauth2_scheme 作為get_current_user的依賴項,然后將get_current_user作為路徑操作函數的依賴項。
... async def get_current_user(token: str = Depends(oauth2_scheme)): pass @app.get("/users/me") async def read_users_me(current_user: User = Depends(get_current_user)): return current_user ...
- 獲取用戶
... 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 ...
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