Coverage for nexios\auth\middleware.py: 95%
22 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
1from __future__ import annotations
3import inspect
4from typing_extensions import Annotated, Doc
6from .base import AuthenticationBackend, UnauthenticatedUser, BaseUser
7from nexios.middlewares.base import BaseMiddleware
8from nexios.http import Request, Response
9import typing
12class AuthenticationMiddleware(BaseMiddleware):
13 """
14 Middleware responsible for handling user authentication.
16 This middleware intercepts incoming HTTP requests, calls the authentication
17 backend to verify user credentials, and attaches the authenticated user to
18 the request scope.
20 Attributes:
21 backend (AuthenticationBackend): The authentication backend used to verify users.
22 """
24 def __init__(
25 self,
26 backend: Annotated[
27 AuthenticationBackend,
28 Doc("The authentication backend responsible for verifying users."),
29 ],
30 ) -> None:
31 """
32 Initializes the authentication middleware with a specified backend.
34 Args:
35 backend (AuthenticationBackend): An instance of the authentication backend.
36 """
37 self.backend = backend
39 async def process_request(
40 self,
41 request: Annotated[
42 Request,
43 Doc("The HTTP request object, containing authentication credentials."),
44 ],
45 response: Annotated[
46 Response,
47 Doc(
48 "The HTTP response object, which may be modified during authentication."
49 ),
50 ],
51 call_next: typing.Callable[..., typing.Awaitable[typing.Any]],
52 ) -> None:
53 """
54 Processes an incoming request by authenticating the user.
56 This method calls the authentication backend, determines if the user is authenticated,
57 and attaches the authenticated user to the request. If authentication fails, the request
58 is assigned an `UnauthenticatedUser` instance.
60 Args:
61 request (Request): The HTTP request object.
62 response (Response): The HTTP response object.
64 Side Effects:
65 - Sets `request.user` to an authenticated user or `UnauthenticatedUser`.
66 - Updates `request.scope["user"]` with the user object.
68 """
69 if not inspect.iscoroutinefunction(self.backend.authenticate):
70 user: typing.Tuple[BaseUser, str] = self.backend.authenticate(
71 request, response
72 ) # type:ignore
73 else:
74 user: typing.Tuple[BaseUser, str] = await self.backend.authenticate(
75 request, response
76 ) # type:ignore
78 if user is None: # type:ignore
79 request.scope["user"] = UnauthenticatedUser()
80 request.scope["auth"] = "no-auth"
81 await call_next()
83 return
85 request.scope["user"] = user[0]
86 request.scope["auth"] = user[-1]
88 await call_next()