Actualmente, estoy tratando de encontrar una manera de usar un _keyfunc personalizado con SlowAPI que me permita acceder a los datos del usuario. La función de cliente por la que quería pasar se ve así:
async def get_limiter_id(current_user: User = Depends(get_current_user)): print(current_user) return str(current_user.retailer_id) limiter = Limiter( key_func= get_limiter_id, default_limits=["200 per day", "50 per hour", "1 per minute"] ) app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) El problema es que no acepta funciones asincrónicas, por lo que si trato de pasar: current_user: User = Depends(get_current_user) como argumento, no funcionará porque hace que la función no sea asíncrona, en cuyo caso el el usuario actual no pasará correctamente, o lo hace asíncrono, pero luego simplemente pasará el objeto coroutine porque no esperó el resultado (lo que no es posible con la forma en que se escribe SlowAPI atm).
Esta es la función get_current_user para mayor claridad:
async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise credentials_exception print(username) token_data = TokenData(username=username) except JWTError: raise credentials_exception user = get_user(fake_user_db, username=token_data.username) if user is None: raise credentials_exception if user.enabled == 0: raise HTTPException(status_code=400, detail="Inactive user") return userUna solución en la que pensé fue agarrar para poner retail_id en el encabezado para poder tener una función personalizada como esta:
def get_retailer_id(request: Request): token = request.headers.get('retailer_id') return retailer_idPero no sé cómo puedo obtener esta información específica del usuario escrita en el encabezado de todas las rutas en la creación del token de portador. ¿Alguna idea sobre cómo podría resolver esto?
Resuelto el problema. No me di cuenta de que podía almacenar esta información personalizada en la carga útil del token (al crear el token) y luego bajarla del encabezado. Aquí hay un poco de duplicación de código, pero es una solución lo suficientemente buena:
def get_retailer_id(request: Request): token = request.headers.get('Authorization') token = token.replace("Bearer ", "") credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token is invalid or payload is corrupt", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) retailer_id: str = payload.get("retailer_id") return str(retailer_id) except Exception: raise credentials_exception