[英]FASTApi authentication injection
My application has an AuthenticateService
implemented as follows:我的应用程序有一个
AuthenticateService
实现如下:
from domain.ports.repositories import ISalesmanRepository
from fastapi import HTTPException, status
from fastapi_jwt_auth import AuthJWT
from fastapi_jwt_auth.exceptions import JWTDecodeError
from shared.exceptions import EntityNotFound
from adapters.api.authentication.config import User
class AuthenticateService:
def __init__(self, user_repo: ISalesmanRepository):
self._repo = user_repo
def __call__(self, auth: AuthJWT) -> User:
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
auth.jwt_required()
user_id = auth.get_jwt_subject()
except JWTDecodeError:
raise credentials_exception
try:
user = self._repo.get_by_id(user_id)
return user
except EntityNotFound:
raise credentials_exception
So the behavior is basically:所以行为基本上是:
The problem is that in every controller implemented I have to repeat the process.问题是在每个 controller 实施中,我必须重复这个过程。 I tried to implement a decorator that injects the user into the controller in case of success but I couldn't.
我试图实现一个装饰器,在成功的情况下将用户注入 controller 但我做不到。 I'm sure that the best way to implement this is to use fastAPI's
Depends
dependency injector.我确信实现这一点的最佳方法是使用 fastAPI 的
Depends
依赖注入器。 Today, a controller looks something like this:今天,controller 看起来像这样:
from typing import Optional
from adapters.api.services import authenticate_service, create_sale_service
from fastapi import APIRouter, Depends
from fastapi_jwt_auth import AuthJWT
from pydantic import BaseModel
router = APIRouter()
class Request(BaseModel):
code: str
value: float
date: str
status: Optional[str] = None
@router.post('/sale')
def create_sale(request: Request, auth: AuthJWT = Depends()):
user = authenticate_service(auth)
result = create_sale_service.handle(
{"salesman": user, "sale": request.dict()}
)
return result.dict()
How can I abstract my authentication so that my controllers look like any of the versions below:如何抽象我的身份验证,以便我的控制器看起来像以下任何版本:
# Option 1: decorator
@router.post('/sale')
@authentication_required
def create_sale(request: Request, user: User): # User is the `__call__` response from `AuthenticateService` class
result = create_sale_service.handle(
{"salesman": user, "sale": request.dict()}
)
return result.dict()
# Option 2:
@router.post('/sale')
def create_sale(request: Request, user: User = Depends(authenticate_service)): # Something like that, using the depends to inject User to me
result = create_sale_service.handle(
{"salesman": user, "sale": request.dict()}
)
return result.dict()
So I read a little more the Depends
documentation and realize whats was going wrong with my attempt to inject the user on controller signature.因此,我阅读了更多
Depends
文档,并意识到我尝试在 controller 签名上注入用户时出了什么问题。
Right way to implement:正确的实现方式:
> AuthService class
class AuthenticateService:
def __init__(self, user_repo: ISalesmanRepository):
self._repo = user_repo
def __call__(self, auth: AuthJWT = Depends()) -> User:
...
authenticate_service = AuthenticateService(user_repository)
> Controller
@router.post('/sale')
def create_sale(request: Request, user: User = Depends(authenticate_service)):
result = create_sale_service.handle(
{"salesman": user, "sale": request.dict()}
)
return result.dict()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.