我有一个端点应该适用于两个不同的用户组,如果用户不属于任一组,我想给出正确的错误消息。对于这些组,我创建了也在其他端点中使用的依赖项:
def is_teacher(
email: str = Depends(get_email),
db=Depends(get_db)
) -> bool:
teacher = ...
if not teacher:
raise HTTPException(
status_code=403, detail=f"User {email} is not a teacher"
)
return True
def is_principal(
email: str = Depends(get_email),
db=Depends(get_db)
) -> bool:
principal = ...
if not principal:
raise HTTPException(
status_code=403, detail=f"User {email} is not a principal"
)
return True
我尝试创建另一个依赖项,例如
def is_teacher_or_principal(
teacher: bool = Depends(is_teacher),
principal: bool = Depends(is_principal)
) -> bool:
if teacher or principal:
return True
raise HTTPException(
status_code=403, detail=f"User {email} is neither principal nor teacher"
)
但这需要用户既是教师又是校长,因为首先解决了依赖项。
我可以使所有依赖项返回 False 而不是引发异常,但我认为我随后需要在所有端点函数中引发异常,这会导致重复的代码。
我还可以直接在
is_teacher_or_principal
函数中评估教师和校长的价值,但这也感觉像是重复的代码。有没有一种方便的方法来实现依赖项的“OR”运算符,或者我可以以某种方式捕获
is_teacher_or_principal
函数中的 HTTPException 并在那里处理它?
FastAPI 提供了一种更优雅的方式来处理这种情况,而无需引发和捕获异常或复制代码。 可以使用
Security
依赖项和
HTTPAuthorizationCredentials
来实现这一点,结合自定义异常处理。
1. 创建一个自定义异常处理程序:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
class NotTeacherOrPrincipal(Exception):
def __init__(self):
self.status_code = 403
self.detail = "User is neither a teacher nor a principal"
app = FastAPI()
@app.exception_handler(NotTeacherOrPrincipal)
async def not_teacher_or_principal_exception_handler(request: Request, exc: NotTeacherOrPrincipal):
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
2. 修改的依赖项以使用
Security
和
HTTPAuthorizationCredentials
:
from fastapi import Depends, HTTPException, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
security = HTTPBearer()
async def is_teacher(
credentials: HTTPAuthorizationCredentials = Security(security),
email: str = Depends(get_email),
db=Depends(get_db)
) -> bool:
teacher = ...
if not teacher:
return False
return True
async def is_principal(
credentials: HTTPAuthorizationCredentials = Security(security),
email: str = Depends(get_email),
db=Depends(get_db)
) -> bool:
principal = ...
if not principal:
return False
return True
3. 创建一个检查任一角色的依赖项:
async def is_teacher_or_principal(
teacher: bool = Depends(is_teacher),
principal: bool = Depends(is_principal)
):
if teacher or principal:
return True
raise NotTeacherOrPrincipal()
4. 在的端点中使用该依赖项:
@app.get("/some_endpoint", dependencies=[Depends(is_teacher_or_principal)])
async def my_endpoint():
# 只有当用户是教师或校长时才会执行此操作
return {"message": "Hello, teacher or principal!"}
解释:
-
我们使用
Security(security)
依赖项来强制所有需要身份验证的路由。 -
is_teacher
和is_principal
依赖项现在只返回True
或False
,而不是引发异常。 -
is_teacher_or_principal
依赖项检查任一角色是否为真,如果两者都为假,则引发自定义异常NotTeacherOrPrincipal
。 -
自定义异常处理程序捕获
NotTeacherOrPrincipal
异常并返回具有适当状态代码和消息的 JSON 响应。
这种方法有几个优点:
- 它避免了引发和捕获异常的需要,这在 FastAPI 中可能很昂贵。
- 它通过将错误处理逻辑移动到一个中心位置来保持代码清洁和可读性。
- 它允许轻松添加新角色并通过简单地创建新的依赖项来重用现有的角色检查。
总的来说,这种方法提供了一种更简洁、更易于维护且更符合 FastAPI 哲学的方式来处理多个依赖项的授权。
标签:python,fastapi From: 78810373