waza-ari / fastapi-keycloak-middleware

A middleware for FastAPI that allows easy authentication and authorisation tailored for Keycloak
MIT License
43 stars 13 forks source link

TypeError: object dict can't be used in 'await' expression #57

Open TOTom opened 1 week ago

TOTom commented 1 week ago

demo code:

import sys
sys.path.append(".")
import uvicorn
from typing import Tuple,List,Dict,Any
from fastapi import FastAPI, Request, Depends
from fastapi_keycloak_middleware import KeycloakConfiguration, setup_keycloak_middleware, AuthorizationMethod
from fastapi_keycloak_middleware import get_user
from fastapi_keycloak_middleware import AuthorizationResult, require_permission, MatchStrategy, get_authorization_result

excluded_routes = [
    "/hello"
]

keycloak_config = KeycloakConfiguration(
    url="http://127.0.0.1:8008/auth/",
    realm="test",
    client_id="clientId",
    client_secret="xxxxxxxxxxxt",
    claims=["sub", "name", "email", "iss"],
    reject_on_missing_claim=True,
    authorization_method=AuthorizationMethod.CLAIM,
    authorization_claim="realm_access_roles"
)

app = FastAPI()

setup_keycloak_middleware(
    app,
    keycloak_configuration = keycloak_config,
    exclude_patterns = excluded_routes,
    user_mapper=map_user
 )

@app.get("/hello")
def hello(request: Request):
    return f'hello'

@app.get("/whoami")
@require_permission(["page-admin"],  match_strategy=MatchStrategy.OR)
def whoami(request: Request):
    return {"userinfo": "Hello World"}

if __name__ == '__main__':
    uvicorn.run('app:app', host="127.0.0.1", port=8007)

if I remove "require_permission" , it works well.

trace log:

INFO:     Started server process [31428]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8007 (Press CTRL+C to quit)
INFO:     127.0.0.1:53420 - "GET /whoami HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "c:\Users\xilex\uio\python\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 411, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 69, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\middleware\errors.py", line 186, in __call__
    raise exc
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi_keycloak_middleware\middleware.py", line 191, in __call__
    await self.app(scope, receive, send)  # Token is valid
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\middleware\exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "c:\Users\xilex\uio\python\Lib\site-packages\starlette\routing.py", line 72, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi\routing.py", line 278, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi\routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi_keycloak_middleware\decorators\require_permission.py", line 111, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\xilex\uio\python\Lib\site-packages\fastapi_keycloak_middleware\decorators\strip_request.py", line 27, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object dict can't be used in 'await' expression

os : windows 10 pro python: Python 3.11.0b4 pip list output:

❯ pip list
Package                     Version     Editable project location
--------------------------- ----------- -------------------------------------------------
fastapi                     0.110.1
fastapi_auth_middleware     1.0.2
fastapi_keycloak            1.0.11
fastapi-keycloak-middleware 1.0.1
pip                         24.1
python-keycloak             4.1.0
requests                    2.31.0
uvicorn                     0.28.1
waza-ari commented 1 week ago

Can you please provide a Minimal, Reproducible Example and use code tags to make the code more readable?

Also, does it change anything if you specify your route using async?

async def whoami():
    return {"userinfo": "Hello World"}
TOTom commented 1 week ago

Can you please provide a Minimal, Reproducible Example and use code tags to make the code more readable?

Also, does it change anything if you specify your route using async?

async def whoami():
    return {"userinfo": "Hello World"}

it works well after add "async".

waza-ari commented 1 week ago

Thanks. I'll look into that soon, ideally the library should support both sync and async routes.