Skip to content

decorator to add per handler annotations #4174

Closed
@gjcarneiro

Description

Long story short

With my custom authentication, trying to have an authentication middleware that requires login by default, except for the handlers specifically annotated with a decorator.

def login_exempt(func: F) -> F:
    func.weblogin_login_exempt = True  # type: ignore
    return func

@web.middleware
async def auth_middleware(
    request: web.Request,
    handler: Callable[[web.Request], Awaitable[web.StreamResponse]],
) -> web.StreamResponse:
    print(handler, hasattr(handler, "weblogin_login_exempt"))
    if not hasattr(handler, "weblogin_login_exempt"):
        session = await weblogin.fetch_session(request)
        if not session:
            raise web.HTTPNotFound(
                text=json.dumps(weblogin.SESSION_NOT_FOUND),
                content_type="application/json",
            )
    return await handler(request)


def create_web_app() -> web.Application:
    app = web.Application(
        middlewares=[weblogin.session_middleware, auth_middleware]
    )
    app.on_startup.append(async_init)
    app.on_shutdown.append(do_shutdown)
    app.router.add_route("GET", "/healthz", healthz)

    app.add_subapp("/s/weblogin", weblogin.create_web_app())
    app.add_subapp("/s/userprefs", userprefs.create_web_app())

Expected behaviour

I expect the handler to have weblogin_login_exempt when it has been decorator, causing the framework to skip the usual auth checks.

Actual behaviour

Instead, at least in the case of a subapp, the handler is a functools.partial(), which means the actual handler function is hidden away.

functools.partial(<function _fix_request_current_app.<locals>.impl at 0x7efbf9fb48c8>, handler=<function login at 0x7efbf9f7ba60>)

Only for the toplevel Application is the handler unmodified. For a subapp, handler is wrapped as a functools.partial() object.

In general, I am either missing something obvious, or there is a lack of an API in aiohttp to achieve this sort of thing. I would like to be able to annotate handlers, somehow, and for middleware to fetch the handler annotations.

Steps to reproduce

Your environment

aiohttp 3.6.1, python 37.3.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions