Writing an access guard with FastAPI decorators indepedent of the route signature

175 views Asked by At

I try to make this code work:

@router.get("/me")
@role_guard(UserRole.USER)
async def read_user_me(request: Request, user: User = Depends(get_current_user)):
    return user.to_base()

So this code works, but it stops working if I remove the request parameter. Ideally I don't want to have an unused parameter in the function and also I want to decouple the annotation / decorator from the function logic. Is there a way to archive this somehow? To inject the needed request parameter on the side of the decorator?

ChatGPT came up with this syntax but it's not working and I'm not sure if there even is a way to make it work. Is there?

def role_guard(role: UserRole):
    """ Minimum required role for that route. Also injects the user object into the route. """
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            request = kwargs.get('request')
            if not request:
                for arg in args:
                    if isinstance(arg, Request):
                        request = arg
                        break

            if request:
                authorization: str = request.headers.get("Authorization")
                ## more logic here

            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Not authenticated",
            )
        if 'request' not in inspect.signature(func).parameters:
            async def wrapper_with_request(request: Request, *args, **kwargs):
                return await wrapper(request=request, *args, **kwargs)
            return wrapper_with_request
        return wrapper
    return decorator

It looks like it could work - but I guess that's just a language model doing its thing.

0

There are 0 answers